evolver-2.30c.dfsg/ 0000755 0001753 0001753 00000000000 11672223713 014433 5 ustar hazelsct hazelsct evolver-2.30c.dfsg/evolver.1 0000644 0001753 0001753 00000006775 11410765113 016211 0 ustar hazelsct hazelsct .\"Modified from man(1) of FreeBSD, the NetBSD mdoc.template, and mdoc.samples.
.\"See Also:
.\"man mdoc.samples for a complete listing of options
.\"man mdoc for the short list of editing options
.\"/usr/share/misc/mdoc.template
.Dd Mon May 19 2003 \" DATE
.Dt Evolver 1 \" Program name and manual section number
.Sh NAME \" Section Header - required - don't modify
.Nm evolver
.\" The following lines are read in generating the apropos(man -k) database. Use only key
.\" words here as the database is built based on the words here and in the .ND line.
.Nd The Surface Evolver, minimize energy of a surface
.Sh SYNOPSIS \" Section Header - required - don't modify
.Nm
.Op Fl adehimqwxy \" [-adehimqwxy]
.Op Fl f Ar file \" [-f file]
.Op Fl pN \" [-pN]
.Op Ar datafile \" Underlined argument - use .Ar anywhere to underline
.Sh DESCRIPTION \" Section Header - required - don't modify
The Surface Evolver is a program that minimizes the energy of a triangulated
surface according to designated energies and constraints. This man page only
documents command line options and environment variables. The full package
and documentation are available at http://www.susqu.edu/brakke/evolver.
.Pp \" Inserts a space
Command line options:
.Bl -tag -width -indent \" Differs from above in tag removed
.It Ar datafile
Text file defining a surface. If omitted, you will be prompted.
.It Fl a
Autoconvert to named quantities when needed (default is on); use "-a-" to
deactivate autoconversion.
.It Fl d
Begin with parser debugging on (equivalent to "debug" runtime command).
Beware of copious output.
.It Fl e
Echo stdin to stdout; meant for testing piped input.
.It Fl f Ar file
After loading datafile, read commands from
.Ar file ,
then command line prompt.
.It Fl h
Print help for command line options.
.It Fl i
Preserve datafile numbers for element id's, rather than renumbering.
.It Fl m
Begin with memory debugging on (equivalent to "memdebug" runtime command).
Beware of copious output.
.It Fl pN
Run with N concurrent processes.
.It Fl q
Convert to named quantities at start (equivalent to "convert_to_quantities"
runtime command).
.It Fl Q
Suppress echoing of "read" section of datafile, and other files read in.
.It Fl w
Exit immediately after any warning or error message; meant for batch runs.
.It Fl x
Exit immediately after any error message; meant for batch runs.
.It Fl y
Break to user prompt after any warning message.
.El \" Ends the list
.Pp
.\" .Sh ENVIRONMENT \" May not be needed
.\" .Bl -tag -width "ENV_VAR_1" -indent \" ENV_VAR_1 is width of the string ENV_VAR_1
.\" .It Ev ENV_VAR_1
.\" Description of ENV_VAR_1
.\" .It Ev ENV_VAR_2
.\" Description of ENV_VAR_2
.\" .El
.Sh ENVIRONMENT VARIABLES
.Bl -tag -width "EVOLVERPATH" -compact
.It EVOLVERPATH
Colon-separated list of paths automatically searched for datafiles, included
files, or help documentation.
.Sh FURTHER DOCUMENTATION
See manual224.pdf in the Evolver distribution, browse evolver.htm in the
doc subdirectory of the distribution, or browse the documentation on-line
at http://www.susqu.edu/brakke/evolver/html/evolver.htm
.Sh WEBSITE
The Surface Evolver home page is http://www.susqu.edu/brakke/evolver.
.Sh BUGS
Send bug reports to brakke@susqu.edu. Please include the datafile and
exact instructions for reproducing the problem.
evolver-2.30c.dfsg/README 0000644 0001753 0001753 00000012567 11410765113 015321 0 ustar hazelsct hazelsct Instructions for installing the Surface Evolver on unix-style systems.
Quick start:
1. Unpack the Evolver archive.
2. In the src subdirectory, edit Makefile to uncomment the lines for
your system.
3. Run "make".
4. Test by running "./evolver ../fe/cube.fe"
Detailed instructions:
1. The Evolver is distributed in a compressed tar archive evolver-2.30.tar.gz
available from http://www.susqu.edu/brakke/evolver. Get this file into a
working directory. The packed archive is about 2MB, unpacks to about 5MB.
You will probably need another 3 or 4 MB to compile.
2. Uncompress the archive with
gunzip evolver-2.30.tar.gz
Extract the files with
tar xvf evolver.tar
This will unpack into three subdirectories: src (source code),
doc (the html version of the manual), and fe (sample datafiles).
The working directory will also contain a PDF version of the manual,
and a man page, evolver.1.
3. Install the man page: copy evolver.1 to some appropriate place on your
manpath, such as /usr/local/share/man/man1. You may have to become root
to have permission to do this.
4. Set the EVOLVERPATH environment variable: Evolver needs to find the initial
datafile and sometimes other files (e.g. command files for the "read"
command, the help documentation files). If the named file is not in the
current directory, then an environment variable called EVOLVERPATH will be
consulted for a directory search list. The datafile directory and the
directory with the HTML documentation files should definitely be included.
The format is the same as the usual PATH environment variable. Set it up
as usual in your system, in .profile or .login or .cshrc or wherever:
Unix C shell:
setenv EVOLVERPATH /usr/you/evolver/fe:/usr/you/evolver/doc
Bourne shell:
EVOLVERPATH=/usr/you/evolver/fe:/usr/you/evolver/doc
export EVOLVERPATH
5. Change to the src subdirectory of your Evolver directory.
6. Modify Makefile for your system. Makefile begins with sets of macro
definitions for various systems. If your system is listed, remove the
comment symbols '#' from start of the appropriate lines. If your system
is not there, use the GENERIC lines, or set up your own. If you do define
your own, be sure to put a corresponding section in include.h.
7. In Makefile, edit the CFLAGS line to have the proper options (optimization,
floating point option, etc.).
8. In Makefile, GRAPH should be the name of a screen graphics interface file.
Use glutgraph.o if possible; most systems have OpenGL/GLUT graphics now.
GLUT graphics uses a separate thread to display graphics, so if you use
GLUT, you must put -DPTHREADS in CFLAGS and put -lpthread in GRAPHLIB.
If not using GLUT, for primitive X windows graphics you can use xgraph.o.
For no built-in screen graphics at all you can use nulgraph.o. GRAPHLIB
should be the appropriate graphics library plus any other libraries needed.
9. If you want to use parallel processes on a multiprocessor machine,
put -DPTHREADS in CFLAGS and put -lpthread in GRAPHLIB. Currently, the
only calculations done in parallel are basic energies and named quantities.
The number of processes actually done in parallel can be controlled
with the -p n command line option.
10. If you want Evolver to be able to use geomview, include -DOOGL in CFLAGS.
11. If you want Evolver to operate in a higher space dimension than the
the default maximum of 4, include -DMAXCOORD=n in CFLAGS, where n is
the maximum space dimension. This sets the upper limit of dimensionality,
and is used for allocating space in data structures.
12. If your system supports the long double data type, you can compute and
print values in higher precision by compiling with -DLONGDOUBLE in CFLAGS.
But this slows computations, and should be used only by precision fanatics.
13. If you wish to use the commands based on the METIS partitioning
software (metis, kmetis, body_metis, and metis_factor), then
you should download the METIS package from,
http://www-users.cs.umn.edu/~karypis/metis/
and "make" the library libmetis.a (on some systems, make complains it
cannot find ranlib, but the resulting libmetis.a still works).
In Evolver's Makefile, add -DMETIS to CFLAGS, and add -lmetis to GRAPHLIB.
You will probably also have to add -L metispath to GRAPHLIB to tell
the linker where to find libmetis.a. Note that METIS is incorporated
in the Windows executable. If you are using hessian commands on very
large surfaces, then metis_factor can be much faster than the other
sparse matrix factoring schemes in Evolver, and I highly recommend it.
14. From the shell command prompt in the src directory, run "make". This
will produce the Evolver executable file named "evolver" in the src
directory. If there are errors, hopefully you will only have to change
the system-specific parts of Makefile and include.h to get things to work.
If significant changes to other files are needed, let me know at
brakke@susqu.edu.
15. Copy the evolver executable to someplace on your PATH, such as
$HOME/bin or /usr/local/bin, or make a link someplace on your PATH to
the evolver executable.
16. Test by opening a new shell and running "evolver cube". Now you
should be able to follow the tutorials in the HTML or printed manual.
End of README
evolver-2.30c.dfsg/fe/ 0000755 0001753 0001753 00000000000 11410765113 015020 5 ustar hazelsct hazelsct evolver-2.30c.dfsg/fe/unshear.cmd 0000755 0001753 0001753 00000005546 11410765113 017167 0 ustar hazelsct hazelsct // unshear.cmd
// Evolver command to get torus fundamental region closer to rectangular.
// Works in either 2 or 3 dimensions. (eventually, just 2D now)
// NOTE: "unshear" needs to change the torus periods, but can't directly
// since torus_periods is a read-only variable (because it is remembered
// as a formula). So the assumption is that the shear entries of the
// torus_periods matrix are variables of particular names, shearij for
// torus_periods[i][j]. (remember indexing starts with 1)
// Programmer: Ken Brakke, brakke@susqu.edu, http://www.susqu.edu/brakke
if not is_defined("shear21") then
errprintf "unshear.cmd assumes torus_periods[2][1] defined as shear21.\n" ;
// 2D version
unshear2 := {
local shifts,vshifts,wrap1,wrap2,wraprest;
// test for horizontal shear
shifts := floor(torus_periods[2][1]/torus_periods[1][1] + .5);
shear21 -= shifts*torus_periods[1][1];
// move vertices over
foreach vertex vv do
{ vshifts := -floor(vv.x*inverse_periods[1][1]+vv.y*inverse_periods[1][2]);
if vshifts != 0 then
wrap_vertex(vv.id,(vshifts imod 32));
};
// change edge wraps
foreach edge ee where ((ee.wrap idiv 64) imod 32) == 1 do
{ wrap1 := ee.wrap imod 64;
wraprest := ee.wrap - wrap1;
if wrap1 > 15 then wrap1 -= 32;
wrap1 += shifts;
ee.wrap := wraprest + (wrap1 imod 32);
};
foreach edge ee where ((ee.wrap idiv 64) imod 32) == 31 do
{ wrap1 := ee.wrap imod 64;
wraprest := ee.wrap - wrap1;
if wrap1 > 15 then wrap1 -= 32;
wrap1 += -shifts;
ee.wrap := wraprest + (wrap1 imod 32);
};
recalc; // get inverse periods set up right for next stage
// test for vertical shear
shifts := floor(torus_periods[1][2]/torus_periods[2][2] + .5);
shear12 -= shifts*torus_periods[2][2];
// move vertices over
foreach vertex vv do
{ vshifts := -floor(vv.x*inverse_periods[2][1]+vv.y*inverse_periods[2][2]);
if vshifts != 0 then
wrap_vertex(vv.id,(vshifts imod 32)*64);
};
// change edge wraps
foreach edge ee where (ee.wrap imod 32) == 1 do
{ wrap2 := (ee.wrap idiv 64) imod 64;
wraprest := ee.wrap - wrap2*64;
if wrap2 > 15 then wrap2 -= 32;
wrap2 += shifts;
ee.wrap := wraprest + (wrap2 imod 32)*64;
};
foreach edge ee where (ee.wrap imod 32) == 31 do
{ wrap2 := (ee.wrap idiv 64) imod 64;
wraprest := ee.wrap - wrap2*64;
if wrap2 > 15 then wrap2 -= 32;
wrap2 -= shifts;
ee.wrap := wraprest + (wrap2 imod 32)*64;
};
}
// 3D version
unshear3 := {
errprintf "Unshear not yet implemented for 3D.\n";
}
// Overall command, just a wrapper
unshear := {
if not torus then
{ errprintf "Unshear only relevant to torus model.\n";
return;
};
if space_dimension == 2 then unshear2
else if space_dimension == 3 then unshear3
else errprintf "Unshear not implemented for space dimension %d\n",
space_dimension;
}
evolver-2.30c.dfsg/fe/quadbbox.cmd 0000755 0001753 0001753 00000012535 11410765113 017323 0 ustar hazelsct hazelsct // quadbbox.cmd
// Finds bounding box for each facet in quadratic model.
// Not suitable for torus model.
// Programmer: Ken Brakke, brakke@susqu.edu, http://www.susqu.edu/brakke
// Usage: Run eboxes or fboxes. Results left in the arrays ebox or fbox
// attributes.
define edge attribute ebox real [6] // xmin,xmax,ymin,ymax,zmin,zmax
define facet attribute fbox real [6]
eboxes := {
local ii,v0,v1,v2,v4,uopt,denom;
if ( !quadratic ) then print "eboxes: Must be in quadratic mode.\n"
else foreach edge ee do
{ ii := 1;
while ( ii <= 3 ) do
{
if ( ii == 1 ) then
{ v0 := ee.vertex[1].x;
v2 := ee.vertex[2].x;
v1 := ee.vertex[3].x;
} else if ( ii == 2 ) then
{ v0 := ee.vertex[1].y;
v2 := ee.vertex[2].y;
v1 := ee.vertex[3].y;
} else
{ v0 := ee.vertex[1].z;
v2 := ee.vertex[2].z;
v1 := ee.vertex[3].z;
} ;
if ( v0 > v1 )
then { set ee ebox[2*ii-1] v1; set ee ebox[2*ii] v0; }
else { set ee ebox[2*ii-1] v0; set ee ebox[2*ii] v1; };
if ( v2 < ee.ebox[2*ii-1] ) then set ee ebox[2*ii-1] v2;
if ( v2 > ee.ebox[2*ii] ) then set ee ebox[2*ii] v2;
denom := v0 - 2*v1 + v2;
if ( denom == 0.0 ) then { ii := ii+1; continue; };
uopt := (-1.5*v0 + 2*v1 - .5*v2)/denom;
if ( uopt <= 0.0 or uopt >= 1.0 )
then { ii := ii+1;continue; };
v4 := 0.5*(1-uopt)*(2-uopt)*v0 + uopt*(2-uopt)*v1
+ 0.5*uopt*(uopt-1)*v2;
if ( v4 < ee.ebox[2*ii-1] ) then set ee ebox[2*ii-1] v4;
if ( v4 > ee.ebox[2*ii] ) then set ee ebox[2*ii] v4;
ii := ii + 1;
}
}
}
fboxes := {
local ii,v0,v1,v2,v3,v4,v5,uopt,denom;
local a11,a12,b1,a21,a22,b2,vopt,vcrit;
eboxes;
if ( ! quadratic ) then print "fboxes: Must be in quadratic mode.\n"
else foreach facet ff do
{
ii := 0; /* which coordinate */
while ( ii < 3 ) do
{ ii := ii + 1; // so can use continue
/* first, edge boxes */
set ff fbox[2*ii-1] ff.edge[1].ebox[2*ii-1];
set ff fbox[2*ii] ff.edge[1].ebox[2*ii];
if ( ff.edge[2].ebox[2*ii-1] < ff.fbox[2*ii-1] )
then set ff fbox[2*ii-1] ff.edge[2].ebox[2*ii-1];
if ( ff.edge[2].ebox[2*ii] > ff.fbox[2*ii] )
then set ff fbox[2*ii] ff.edge[2].ebox[2*ii];
if ( ff.edge[3].ebox[2*ii-1] < ff.fbox[2*ii-1] )
then set ff fbox[2*ii-1] ff.edge[3].ebox[2*ii-1];
if ( ff.edge[3].ebox[2*ii] > ff.fbox[2*ii] )
then set ff fbox[2*ii] ff.edge[3].ebox[2*ii];
if ( ii == 1 ) then
{ v0 := ff.edge[1].vertex[1].x;
v1 := ff.edge[1].vertex[3].x;
v2 := ff.edge[1].vertex[2].x;
v3 := ff.edge[3].vertex[3].x;
v4 := ff.edge[2].vertex[3].x;
v5 := ff.edge[2].vertex[2].x;
} else if ( ii == 2 ) then
{ v0 := ff.edge[1].vertex[1].y;
v1 := ff.edge[1].vertex[3].y;
v2 := ff.edge[1].vertex[2].y;
v3 := ff.edge[3].vertex[3].y;
v4 := ff.edge[2].vertex[3].y;
v5 := ff.edge[2].vertex[2].y;
} else
{ v0 := ff.edge[1].vertex[1].z;
v1 := ff.edge[1].vertex[3].z;
v2 := ff.edge[1].vertex[2].z;
v3 := ff.edge[3].vertex[3].z;
v4 := ff.edge[2].vertex[3].z;
v5 := ff.edge[2].vertex[2].z;
};
// x_u coeff of u
a11 := v0 - 2*v1 + v2;
// x_u coeff of v
a12 := v0 - v1 - v3 + v4;
// x_u rhs
b1 := -(-1.5*v0 + 2*v1 - .5*v2);
// x_v coeff of u
a21 := v0 - v1 - v3 + v4;
// x_v coeff of v
a22 := v0 - 2*v3 + v5;
// x_v rhs
b2 := -(-1.5*v0 + 2*v3 - 0.5*v5);
// solve for critical point
denom := a11*a22 - a12*a21;
if ( denom == 0.0 ) then continue;
uopt := (b1*a22 - b2*a12)/denom;
vopt := (a11*b2 - a21*b1)/denom;
if ( uopt <= 0.0 ) then continue;
if ( vopt <= 0.0 ) then continue;
if ( uopt+vopt >= 2.0 ) then continue;
vcrit := 0.5*(uopt+vopt-1)*(uopt+vopt-2)*v0
+ uopt*(2-uopt-vopt)*v1
+ 0.5*uopt*(uopt-1)*v2
+ vopt*(2-uopt-vopt)*v3
+ uopt*vopt*v4
+ 0.5*vopt*(vopt-1)*v5;
if ( vcrit < ff.fbox[2*ii-1] ) then set ff fbox[2*ii-1] vcrit;
if ( vcrit > ff.fbox[2*ii] ) then set ff fbox[2*ii] vcrit;
}
}
}
evolver-2.30c.dfsg/fe/ansurf.cmd 0000755 0001753 0001753 00000004433 11410765113 017012 0 ustar hazelsct hazelsct // ansurf.cmd
// Surface Evolver command to produce file of ANSYS input for
// vertices, edges, and faces to produce a surface
// for ANSYS meshing. Beware this is a very simple-minded
// translation to ANSYS format.
// Modified Feb. 2006 to not assume consecutive numbering of elements.
// Programmer: Ken Brakke, brakke@susqu.edu, http://www.susqu.edu/brakke
// usage: ansurf >>> "filename"
// Attributes to hold ANSYS numbering of elements
define vertex attribute ansurf_knumber real
define edge attribute ansurf_lnumber real
define facet attribute ansurf_alnumber real
// vertices as ANSYS keypoints
ansurf_nodes := {
local knumber;
knumber := 0;
foreach vertex vv do
{ printf "k,,%20.15g,%20.15g,%20.15g\n",x,y,z;
knumber += 1;
vv.ansurf_knumber := knumber;
}
}
ansurf_edges := {
local lnumber;
lnumber := 0;
if (quadratic) then
foreach edge ee do
{ printf "larc,%g,%g,%g\n",ee.vertex[1].ansurf_knumber,
ee.vertex[2].ansurf_knumber,ee.vertex[3].ansurf_knumber;
lnumber += 1;
ee.ansurf_lnumber := lnumber;
}
else
foreach edge ee do
{ printf "l,%g,%g\n",ee.vertex[1].ansurf_knumber,
ee.vertex[2].ansurf_knumber;
lnumber += 1;
ee.ansurf_lnumber := lnumber;
}
}
ansurf_faces := {
local alnumber;
alnumber := 0;
foreach facet ff do
{ printf "al,%g,%g,%g\n",
ff.edge[1].ansurf_lnumber,ff.edge[2].ansurf_lnumber,
ff.edge[3].ansurf_lnumber;
alnumber += 1;
ff.ansurf_alnumber := alnumber;
}
}
// define volumes, one per body
ansurf_bodies := { foreach body bb do
{ // select areas
local flag;
flag := 0;
foreach bb.facet ff do
{ if flag then printf "ASEL,A,AREA,,%g,%g\n",ff.ansurf_alnumber,
ff.ansurf_alnumber
else printf "ASEL,S,AREA,,%g,%g\n",ff.ansurf_alnumber,
ff.ansurf_alnumber;
flag := 1;
};
printf "VA,ALL\n";
}
}
// define areas
ansurf := { printf "/PREP7\n";
printf "/NOPR\n";
ansurf_nodes;
ansurf_edges;
ansurf_faces;
ansurf_bodies;
}
// Usage: ansurf >>> "ansys_file"
evolver-2.30c.dfsg/fe/x3d.cmd 0000755 0001753 0001753 00000004676 11410765113 016223 0 ustar hazelsct hazelsct // x3d.cmd
// Surface Evolver script to export surface as an X3D file for 3D viewing
// in a browser.
// Usage: x3d >>> "filename.x3d"
// Programmer: Ken Brakke, brakke@susqu.edu, http://www.susqu.edu/brakke
define rgb real[16][4];
rgb[1][1] := 0.0; rgb[1][2] := 0.0; rgb[1][3] := 0.0;
rgb[2][1] := 0.0; rgb[2][2] := 0.0; rgb[2][3] := 1.;
rgb[3][1] := 0.0; rgb[3][2] := 1.; rgb[3][3] := 0.0;
rgb[4][1] := 0.0; rgb[4][2] := 1.; rgb[4][3] := 1.;
rgb[5][1] := 1.; rgb[5][2] := 0.0; rgb[5][3] := 0.0;
rgb[6][1] := 1.; rgb[6][2] := 0.0; rgb[6][3] := 1.;
rgb[7][1] := 1.; rgb[7][2] := 0.5; rgb[7][3] := 0.;
rgb[8][1] := .6; rgb[8][2] := .6; rgb[8][3] := .6;
rgb[9][1] := .3; rgb[9][2] := .3; rgb[9][3] := .3;
rgb[10][1] := .3; rgb[10][2] := .8; rgb[10][3] := 1.;
rgb[11][1] := .5; rgb[11][2] := 1.; rgb[11][3] := .5;
rgb[12][1] := .5; rgb[12][2] := 1.; rgb[12][3] := 1.;
rgb[13][1] := 1.; rgb[13][2] := .5; rgb[13][3] := .5;
rgb[14][1] := 1.; rgb[14][2] := .5; rgb[14][3] := 1;
rgb[15][1] := 1.; rgb[15][2] := 1.; rgb[15][3] := .0;
rgb[16][1] := 1; rgb[16][2] := 1; rgb[16][3] := 1;
x3d := {
printf"\n";
printf"\n";
printf "\n";
printf " \n";
printf " \n",datafilename;
printf " \n";
printf " \n";
printf " \n";
printf " \n";
printf " \n";
foreach facet ff where color >= 0 do
{ printf " \n";
printf " \n";
printf " \n", rgb[ff.color+1][1],
rgb[ff.color+1][2],rgb[ff.color+1][3];
printf " \n";
printf " \n";
printf " \n",
ff.vertex[1].x,ff.vertex[1].y,ff.vertex[1].z,
ff.vertex[2].x,ff.vertex[2].y,ff.vertex[2].z,
ff.vertex[3].x,ff.vertex[3].y,ff.vertex[3].z;
printf " \n";
printf " \n";
};
printf " \n";
printf " \n";
printf "\n";
}
evolver-2.30c.dfsg/fe/octa.fe 0000644 0001753 0001753 00000002113 11410765113 016257 0 ustar hazelsct hazelsct // octa.fe
// Evolver data file for symmetric nonstable film in octahedral frame.
// Pop edges, iterate, then pop vertices.
vertices
1 0 0 0
2 2 0 0 fixed
3 0 2 0 fixed
4 -2 0 0 fixed
5 0 -2 0 fixed
6 0 0 2 fixed
7 0 0 -2 fixed
edges
1 2 3 fixed
2 3 4 fixed
3 4 5 fixed
4 5 2 fixed
5 2 6 fixed
6 3 6 fixed
7 4 6 fixed
8 5 6 fixed
9 7 2 fixed
10 7 3 fixed
11 7 4 fixed
12 7 5 fixed
13 1 2
14 1 3
15 1 4
16 1 5
17 1 6
18 7 1
faces
1 13 1 -14
2 14 2 -15
3 15 3 -16
4 16 4 -13
5 13 5 -17
6 14 6 -17
7 15 7 -17
8 16 8 -17
9 9 -13 -18
10 10 -14 -18
11 11 -15 -18
12 12 -16 -18
read
// Typical evolution, winding up with the central tetrahedral point
// version of the octahedral film. This evolution is not real tidy,
// taking several more pops before settling down, but is just recorded
// from a trial sequence without tidying up.
gogo := { o; U; g 20; t .1; g 10; o; g 20; u; V; t .1; o; g 12; o; u;
V; u; V; g 10; t .1; o; V; g 10; t .1; u; V; g 10; t .1; g 10;
}
evolver-2.30c.dfsg/fe/gaussref.cmd 0000755 0001753 0001753 00000004625 11410765113 017336 0 ustar hazelsct hazelsct // gaussref.cmd
// Refining using Gauss map as criterion.
// Refines edges where difference in normal
// exceeds user-set amount.
// Programmer: Ken Brakke, brakke@susqu.edu, http://www.susqu.edu/brakke
// Usage: set the variable gaussref_tolerance, and do gaussref.
// Set by user; difference in normals in radians
gaussref_tolerance := 0.3
gaussref := {
local ax,ay,az,bx,by,bz,diff,maga,magb,alen,maxdiff,triples,blen;
local gaussref_count;
gaussref_count := 0;
foreach edge eee do
{ if max ( eee.vertex[1].edge,valence) <= 2 and
max ( eee.vertex[2].edge,valence) <= 2 then
{ ax := eee.vertex[1].vertexnormal[1];
ay := eee.vertex[1].vertexnormal[2];
az := eee.vertex[1].vertexnormal[3];
bx := eee.vertex[2].vertexnormal[1];
by := eee.vertex[2].vertexnormal[2];
bz := eee.vertex[2].vertexnormal[3];
diff := pi/2 - abs(pi/2 - acos(ax*bx+ay*by+az*bz)) ;
if ( diff > gaussref_tolerance )
then {
refine eee; gaussref_count += 1;
}
}
else if eee.valence == 2 then
{ ax := eee.facet[1].x[1];
ay := eee.facet[1].x[2];
az := eee.facet[1].x[3];
bx := eee.facet[2].x[1];
by := eee.facet[2].x[2];
bz := eee.facet[2].x[3];
maga := sqrt(ax^2+ay^2+az^2);
magb := sqrt(bx^2+by^2+bz^2);
diff := pi/2 - abs(pi/2 - acos((ax*bx+ay*by+az*bz)/maga/magb)) ;
if ( diff > gaussref_tolerance )
then {
refine eee; gaussref_count += 1;
}
}
else if eee.valence >= 3 then
{ // check bend in continuation triple lines
ax := eee.x;
ay := eee.y;
az := eee.z;
alen := eee.length;
maxdiff := 0;
triples := 0;
foreach eee.vertex vvv do
{ foreach vvv.edge eeee where (eeee.id != eee.id) and (valence >= 3) do
{ triples += 1;
bx := eeee.x;
by := eeee.y;
bz := eeee.z;
blen := eeee.length;
diff := pi/2 - abs(pi/2 - acos((ax*bx+ay*by+az*bz)/alen/blen)) ;
if ( diff > gaussref_tolerance )
then {
if ( diff > maxdiff ) then maxdiff := diff;
}
}
};
if ( (triples <= 1) and (maxdiff > gaussref_tolerance) )
then {
refine eee; gaussref_count += 1;
}
}
};
printf "Edges refined by gaussref: %d\n",gaussref_count;
}
evolver-2.30c.dfsg/fe/mound.fe 0000644 0001753 0001753 00000004032 11410765113 016455 0 ustar hazelsct hazelsct // mound.fe
// Evolver data for drop of prescribed volume sitting on plane with gravity.
// Contact angle with plane can be varied.
PARAMETER angle = 90 // interior angle between plane and surface, degrees
gravity_constant 0 // start with gravity off
#define WALLT (-cos(angle*pi/180)) // virtual tension of facet on plane
constraint 1 /* the table top */
formula: x3 = 0
energy: // for contact angle
e1: -(WALLT*y)
e2: 0
e3: 0
vertices
1 0.0 0.0 0.0 constraint 1 /* 4 vertices on plane */
2 1.0 0.0 0.0 constraint 1
3 1.0 1.0 0.0 constraint 1
4 0.0 1.0 0.0 constraint 1
5 0.0 0.0 1.0
6 1.0 0.0 1.0
7 1.0 1.0 1.0
8 0.0 1.0 1.0
9 2.0 2.0 0.0 fixed /* for table top */
10 2.0 -1.0 0.0 fixed
11 -1.0 -1.0 0.0 fixed
12 -1.0 2.0 0.0 fixed
edges /* given by endpoints and attribute */
1 1 2 constraint 1 /* 4 edges on plane */
2 2 3 constraint 1
3 3 4 constraint 1
4 4 1 constraint 1
5 5 6
6 6 7
7 7 8
8 8 5
9 1 5
10 2 6
11 3 7
12 4 8
13 9 10 no_refine fixed /* for table top */
14 10 11 no_refine fixed
15 11 12 no_refine fixed
16 12 9 no_refine fixed
faces /* given by oriented edge loop */
1 1 10 -5 -9
2 2 11 -6 -10
3 3 12 -7 -11
4 4 9 -8 -12
5 5 6 7 8
7 13 14 15 16 no_refine density 0 fixed /* table top for display */
bodies /* one body, defined by its oriented faces */
1 1 2 3 4 5 volume 1 density 1
read
re := {refine edges where on_constraint 1 }
// Typical evolution
gogo := { re; g 5; r; g 5; r; g 5; hessian; hessian; }
// Evolution with 45 degree contact angle
gogo2 := { angle := 45; re; g 5; V;V; r; g 5; V;V; r; g 5; hessian; hessian; }
// Evolution with 90 contact and high gravity
gogo3 := { angle := 90; G 5; re; g 5; r; g 5; r; g 5; hessian; hessian; }
// Evolution with 90 contact and negative gravity, i.e. pendant drop
gogo4 := { angle := 90; G -2; re; g 5; r; g 5; r; g 5; hessian; hessian; }
// Pendant drop falling off ceiling
gogo5 := { angle := 90; G -5; re; g 10; t .1; unset vertex constraint 1; g 3; }
evolver-2.30c.dfsg/fe/iges128.cmd 0000755 0001753 0001753 00000017335 11410765113 016703 0 ustar hazelsct hazelsct // iges128.cmd
// Surface Evolver script to write IGES file for surface, using IGES
// rational B-spline entity (type 128).
// Documentation on IGES format: http://www.iges5x.org/taxonomy/
// Programmer: Ken Brakke, brakke@susqu.edu, http://www.susqu.edu/brakke
// usage: iges >>> "filename.igs"
// Set up color translation array
define iges_colors integer [16];
//iges_colors[black] := 1
iges_colors[red] := 2
iges_colors[green] := 3
iges_colors[blue] := 4
iges_colors[yellow] := 5
iges_colors[magenta] := 6
iges_colors[cyan] := 7
iges_colors[white] := 8
iges_colors[brown] := -1 // using colors defined at start of directory
iges_colors[lightgray] := -3
iges_colors[darkgray] := -5
iges_colors[lightblue] := -7
iges_colors[lightgreen] := -9
iges_colors[lightcyan] := -11
iges_colors[lightred] := -13
iges_colors[lightmagenta] := -15
iges := {
// Flag section
// Don't need this since not doing binary or compressed format.
// Start section
start_counter := 0;
start_counter += 1;
printf "%-72sS%07d\n","IGES version of Surface Evolver surface",start_counter;
start_counter += 1;
printf " %-69sS%07d\n",datafilename,start_counter;
start_counter += 1;
printf "%-72sS%07d\n","Created using iges.cmd Evolver script.",
start_counter;
// Global section
global_counter := 0;
global_counter += 1;
printf "%-72sG%07d\n","1H,,1H;,",global_counter;
global_counter += 1;
printf "%02dH%-69sG%07d\n",sizeof("Surface Evolver"),"Surface Evolver,",
global_counter;
global_counter += 1;
message := sprintf "%s,",datafilename;
printf "%02dH%-69sG%07d\n",sizeof(datafilename),message,global_counter;
global_counter += 1;
printf "%02dH%-69sG%07d\n",sizeof("Surface Evolver"),"Surface Evolver,",
global_counter;
global_counter += 1;
printf "%02dH%-69sG%07d\n",sizeof("Surface Evolver"),"Surface Evolver,",
global_counter;
global_counter += 1;
printf "%-72sG%07d\n","32,75,6,75,15,,1.0,1,2HIN,32768,0.0394,",
global_counter;
global_counter += 1;
printf "%-72sG%07d\n","15H00000000.000000,", global_counter; // date
xmax := max(vertex,abs(x));
ymax := max(vertex,abs(y));
zmax := max(vertex,abs(z));
maxsize := (xmax > ymax) ? xmax : ymax;
maxsize := (zmax > maxsize) ? zmax : maxsize;
message := sprintf "%g,%g,",maxsize/10000000,maxsize;
global_counter += 1;
printf "%-72sG%07d\n",message, global_counter;
global_counter += 1;
printf "%02dH%-69sG%07d\n",sizeof("Name of author"),"Name of author,",
global_counter;
global_counter += 1;
printf "%02dH%-69sG%07d\n",sizeof("Author's organization"),
"Author's organization,", global_counter;
global_counter += 1;
printf "%-72sG%07d\n","15H00000000.000000;", global_counter; // date
// Directory entry section. Each entry 20 8-char fields on two lines.
// Fields with default values
entype := 0; // 1 and 11
paramdata := 1; // 2
structure := 0; // 3
linefont := 0; // 4
level := 0; // 5
view := 0; // 6
transmat := 0; // 7
label := 0; // 8
status := "00000000"; // 9; actually 4 two-digit numbers
directory_counter := 0; // 10 and 20
lineweight := 0; // 12
colornum := 0; // 13
paramcount := 0; // 14
form := 0; // 15
reserved := " 0"; // 16 and 17
entlabel := "entity"; // 18
entsubscr := 0; // 19
// Color definitions for those Evolver colors not supplied in IGES
entype := 314;
paramcount := 1;
status := "00000200";
approxcolor := 7; // incompetent systems default to cyan
entlabel := "COLOR";
form := 0;
for ( cinx := 1 ; cinx <= 8 ; cinx += 1 )
{ directory_counter += 1;
printf "%8d%8d%8d%8d%8d%8d%8d%8d%8sD%7d\n",entype,paramdata,structure,
linefont,level,view,transmat,label,status,directory_counter;
directory_counter += 1;
printf "%8d%8d%8d%8d%8d%8s%8s%8s%8dD%7d\n",entype,lineweight,
approxcolor,
paramcount,form,reserved,reserved,entlabel,entsubscr,directory_counter;
paramdata += 1;
};
// Facets as "rational b-spline" types
entype := 128;
status := "00000000";
paramcount := 7; // lines of parameters
form := 8;
entlabel := " FACET";
define facet attribute fpdata integer;
define facet attribute fdir integer;
foreach facet ff do
{ ff.fpdata := paramdata;
entsubscr := ff.id;
directory_counter += 1; ff.fdir := directory_counter;
printf "%8d%8d%8d%8d%8d%8d%8d%8d%8sD%7d\n",entype,paramdata,structure,
linefont,level,view,transmat,label,status,directory_counter;
directory_counter += 1;
printf "%8d%8d%8d%8d%8d%8s%8s%8s%8dD%7d\n",entype,lineweight,
iges_colors[ff.color],
paramcount,form,reserved,reserved,entlabel,entsubscr,directory_counter;
paramdata += paramcount;
};
// Parameter data section
parameter_counter := 1;
// Color definitions
dirnum := 1; // corresponding directory line
printf "%-64s%8dP%7d\n","314,100.,50.,0.;",dirnum,parameter_counter; // brown
parameter_counter += 1; dirnum += 2;
printf "%-64s%8dP%7d\n","314,60.,60.,60.;",dirnum,parameter_counter; // l. gray
parameter_counter += 1; dirnum += 2;
printf "%-64s%8dP%7d\n","314,30.,30.,30.;",dirnum,parameter_counter; // d. gray
parameter_counter += 1; dirnum += 2;
printf "%-64s%8dP%7d\n","314,30,80,100;",dirnum,parameter_counter; // l. blue
parameter_counter += 1; dirnum += 2;
printf "%-64s%8dP%7d\n","314,50,100,50;",dirnum,parameter_counter; // l. grn
parameter_counter += 1; dirnum += 2;
printf "%-64s%8dP%7d\n","314,50,100,100;",dirnum,parameter_counter; // l. cyan
parameter_counter += 1; dirnum += 2;
printf "%-64s%8dP%7d\n","314,100,50,50;",dirnum,parameter_counter; // l. red
parameter_counter += 1; dirnum += 2;
printf "%-64s%8dP%7d\n","314,100,50,100;",dirnum,parameter_counter; // l. mag.
// Facets
entype := 128;
k_1 := 1; // knots-1
k_2 := 1; //
m_1 := 1; // degree
m_2 := 1; //
prop1 := 0; // not closed in first paramter
prop2 := 0; // not closed in second parameter
prop3 := 1; // polynomial instead of rational
prop4 := 0; // nonperiodic in first parameter
prop5 := 0; // nonperiodic in second parameter
minu := 0;
maxu := 1;
minv := 0;
maxv := 1;
foreach facet ff do
{ parameter_counter += 1;
if ff.fpdata != parameter_counter then
errprintf
"ERROR: bad facet parameter line number, facet %d. Is %d, should be %d.\n",
ff.id,parameter_counter,ff.fpdata;
message := sprintf "%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,",entype,k_1,k_2,m_1,m_2,
prop1,prop2,prop3,prop4,prop5;
printf "%-64s%8dP%7d\n",message,ff.fdir,parameter_counter;
message := "0.0,0.0,1.0,1.0,0.0,0.0,1.0,1.0,1.0,1.0,1.0,1.0,";
parameter_counter += 1;
printf "%-64s%8dP%7d\n",message,ff.fdir,parameter_counter;
message := sprintf "%9.7f,%9.7f,%9.7f,",
ff.vertex[1].x,ff.vertex[1].y,ff.vertex[1].z;
parameter_counter += 1;
printf "%-64s%8dP%7d\n",message,ff.fdir,parameter_counter;
message := sprintf "%9.7f,%9.7f,%9.7f,",
ff.vertex[2].x,ff.vertex[2].y,ff.vertex[2].z;
parameter_counter += 1;
printf "%-64s%8dP%7d\n",message,ff.fdir,parameter_counter;
message := sprintf "%9.7f,%9.7f,%9.7f,",
ff.vertex[3].x,ff.vertex[3].y,ff.vertex[3].z;
parameter_counter += 1;
printf "%-64s%8dP%7d\n",message,ff.fdir,parameter_counter;
message := sprintf "%9.7f,%9.7f,%9.7f,",
ff.vertex[3].x,ff.vertex[3].y,ff.vertex[3].z;
parameter_counter += 1;
printf "%-64s%8dP%7d\n",message,ff.fdir,parameter_counter;
message := "0.0,1.0,0.0,1.0;"; //minu,maxu,minv,maxv;
parameter_counter += 1;
printf "%-64s%8dP%7d\n",message,ff.fdir,parameter_counter;
};
// Terminate section
printf "S%07dG%07dD%07dP%07d%40sT0000001\n",start_counter,global_counter,
directory_counter,parameter_counter," ";
}
evolver-2.30c.dfsg/fe/rewrap.cmd 0000755 0001753 0001753 00000004024 11410765113 017010 0 ustar hazelsct hazelsct // rewrap.cmd
// Commands to rewrap torus vertices and edges to get them nicely
// within unit cell. This version does 3D; for 2D see rewrap2.cmd.
// Moves vertices at most one period at a time, so you may have to
// repeat if things are very bad to start with.
// Uses torus wrap representation and wrap_vertex builtin command.
// Usage: rewrap
// Programmer: Ken Brakke, brakke@susqu.edu, http://www.susqu.edu/brakke
rewrap := {
if space_dimension != 3 then
{ errprintf"rewrap is for space dimension 3; for 2D use rewrap2.cmd.\n";
return;
};
define body attribute old_volume real; // so can adjust volconst
set body old_volume volume;
foreach vertex vv where vv.x*inverse_periods[1][1]+vv.y*inverse_periods[1][2]
+ vv.z*inverse_periods[1][3] < 0 do wrap_vertex(vv.id,1);
foreach vertex vv where vv.x*inverse_periods[1][1]+vv.y*inverse_periods[1][2]
+ vv.z*inverse_periods[1][3] >= 1 do wrap_vertex(vv.id,31);
foreach vertex vv where vv.x*inverse_periods[2][1]+vv.y*inverse_periods[2][2]
+ vv.z*inverse_periods[2][3] < 0 do wrap_vertex(vv.id,64);
foreach vertex vv where vv.x*inverse_periods[2][1]+vv.y*inverse_periods[2][2]
+ vv.z*inverse_periods[2][3] >= 1 do wrap_vertex(vv.id,1984);
foreach vertex vv where vv.x*inverse_periods[3][1]+vv.y*inverse_periods[3][2]
+ vv.z*inverse_periods[3][3] < 0 do wrap_vertex(vv.id,4096);
foreach vertex vv where vv.x*inverse_periods[3][1]+vv.y*inverse_periods[3][2]
+ vv.z*inverse_periods[3][3] >= 1 do wrap_vertex(vv.id,126976);
recalc;
// Adjust volconst
local torvol;
torvol := abs((torus_periods[1][1]*torus_periods[2][2]
- torus_periods[1][2]*torus_periods[2][1])*torus_periods[3][3]
+ (torus_periods[1][2]*torus_periods[2][3]
- torus_periods[1][3]*torus_periods[2][2])*torus_periods[3][1]
+ (torus_periods[1][3]*torus_periods[2][1]
- torus_periods[1][1]*torus_periods[2][3])*torus_periods[3][2]);
set body volconst floor((old_volume - volume - volconst)/torvol+.5)*torvol;
}
evolver-2.30c.dfsg/fe/simplex3.fe 0000644 0001753 0001753 00000000765 11410765113 017110 0 ustar hazelsct hazelsct // simplex3.fe
// Evolver data for bubble in 4-space. Initially simplex.
// Evolves into 3-sphere in 4-space.
SIMPLEX_REPRESENTATION
SPACE_DIMENSION 4
SURFACE_DIMENSION 3
vertices
1 0 0 0 0
2 1 0 0 0
3 0 1 0 0
4 0 0 1 0
5 0 0 0 1
faces /* given as oriented vertex list */
1 2 3 4 5
2 3 4 5 1
3 4 5 1 2
4 5 1 2 3
5 1 2 3 4
bodies
1 1 2 3 4 5 volume .04
read
// Typical evolution
gogo := { r; g 5; U; g 10; r; g 10; r; g 20; r; g 20; }
evolver-2.30c.dfsg/fe/quadmeet.cmd 0000755 0001753 0001753 00000014754 11410765113 017330 0 ustar hazelsct hazelsct // quadmeet.cmd
// For detecting intersection of quadratic facets in 3D
// Not suitable for torus model.
// Needs quadbbox.cmd to be loaded first.
// Programmer: Ken Brakke, brakke@susqu.edu, http://www.susqu.edu/brakke
// Usage: quadmeet
// Results: Prints id numbers of intersecting facets.
tiny := 1e-20 // criterion for dist^2 = 0
quadmeet := {
local xa1,xa2,xa3,xa4,xa5,xa6;
local ya1,ya2,ya3,ya4,ya5,ya6;
local za1,za2,za3,za4,za5,za6;
local xb1,xb2,xb3,xb4,xb5,xb6;
local yb1,yb2,yb3,yb4,yb5,yb6;
local zb1,zb2,zb3,zb4,zb5,zb6;
local eps,ua,va,ub,vb,xa,ya,za,xb,yb,zb,dx,dy,dz,dd;
local xau,xav,yau,yav,zau,zav;
local xbu,xbv,ybu,ybv,zbu,zbv;
local uagrad,vagrad,ubgrad,vbgrad,tt;
fboxes; // find facet bounding boxes
// test all facet pairs
foreach facet fa do
{ foreach facet fb where fb.id > fa.id do
{ // first, check bounding boxes
if ( fb.fbox[1] >= fa.fbox[2] or
fb.fbox[2] <= fa.fbox[1] or
fb.fbox[3] >= fa.fbox[4] or
fb.fbox[4] <= fa.fbox[3] or
fb.fbox[5] >= fa.fbox[6] or
fb.fbox[6] <= fa.fbox[5] ) then continue;
// extract coordinates
xa1 := fa.edge[1].vertex[1].x;
xa2 := fa.edge[1].vertex[3].x;
xa3 := fa.edge[1].vertex[2].x;
xa4 := fa.edge[3].vertex[3].x;
xa5 := fa.edge[2].vertex[3].x;
xa6 := fa.edge[2].vertex[2].x;
ya1 := fa.edge[1].vertex[1].y;
ya2 := fa.edge[1].vertex[3].y;
ya3 := fa.edge[1].vertex[2].y;
ya4 := fa.edge[3].vertex[3].y;
ya5 := fa.edge[2].vertex[3].y;
ya6 := fa.edge[2].vertex[2].y;
za1 := fa.edge[1].vertex[1].z;
za2 := fa.edge[1].vertex[3].z;
za3 := fa.edge[1].vertex[2].z;
za4 := fa.edge[3].vertex[3].z;
za5 := fa.edge[2].vertex[3].z;
za6 := fa.edge[2].vertex[2].z;
xb1 := fb.edge[1].vertex[1].x;
xb2 := fb.edge[1].vertex[3].x;
xb3 := fb.edge[1].vertex[2].x;
xb4 := fb.edge[3].vertex[3].x;
xb5 := fb.edge[2].vertex[3].x;
xb6 := fb.edge[2].vertex[2].x;
yb1 := fb.edge[1].vertex[1].y;
yb2 := fb.edge[1].vertex[3].y;
yb3 := fb.edge[1].vertex[2].y;
yb4 := fb.edge[3].vertex[3].y;
yb5 := fb.edge[2].vertex[3].y;
yb6 := fb.edge[2].vertex[2].y;
zb1 := fb.edge[1].vertex[1].z;
zb2 := fb.edge[1].vertex[3].z;
zb3 := fb.edge[1].vertex[2].z;
zb4 := fb.edge[3].vertex[3].z;
zb5 := fb.edge[2].vertex[3].z;
zb6 := fb.edge[2].vertex[2].z;
// Find minimum distance by Newton's Method
eps := .2; // edge guard
ua := .7; va := .6; ub := .71; vb := .67;
while ( eps > 1e-6 ) do
{
xa := 0.5*(ua+va-1)*(ua+va-2)*xa1 + ua*(2-ua-va)*xa2
+ 0.5*ua*(ua-1)*xa3 + va*(2-ua-va)*xa4
+ ua*va*xa5 + 0.5*va*(va-1)*xa6;
ya := 0.5*(ua+va-1)*(ua+va-2)*ya1 + ua*(2-ua-va)*ya2
+ 0.5*ua*(ua-1)*ya3 + va*(2-ua-va)*ya4
+ ua*va*ya5 + 0.5*va*(va-1)*ya6;
za := 0.5*(ua+va-1)*(ua+va-2)*za1 + ua*(2-ua-va)*za2
+ 0.5*ua*(ua-1)*za3 + va*(2-ua-va)*za4
+ ua*va*za5 + 0.5*va*(va-1)*za6;
xb := 0.5*(ub+vb-1)*(ub+vb-2)*xb1 + ub*(2-ub-vb)*xb2
+ 0.5*ub*(ub-1)*xb3 + vb*(2-ub-vb)*xb4
+ ub*vb*xb5 + 0.5*vb*(vb-1)*xb6;
yb := 0.5*(ub+vb-1)*(ub+vb-2)*yb1 + ub*(2-ub-vb)*yb2
+ 0.5*ub*(ub-1)*yb3 + vb*(2-ub-vb)*yb4
+ ub*vb*yb5 + 0.5*vb*(vb-1)*yb6;
zb := 0.5*(ub+vb-1)*(ub+vb-2)*zb1 + ub*(2-ub-vb)*zb2
+ 0.5*ub*(ub-1)*zb3 + vb*(2-ub-vb)*zb4
+ ub*vb*zb5 + 0.5*vb*(vb-1)*zb6;
dx := xa-xb; dy := ya-yb; dz := za - zb;
dd := dx*dx + dy*dy + dz*dz;
if ( dd < tiny ) then break;
xau := (ua + va - 1.5)*xa1 + (2-2*ua-va)*xa2 + (ua-0.5)*xa3
- va*xa4 + va*xa5;
xav := (ua + va - 1.5)*xa1 - ua*xa2 +(2-ua-2*va)*xa4 + ua*xa5
+ (va - 0.5)*xa6;
yau := (ua + va - 1.5)*ya1 + (2-2*ua-va)*ya2 + (ua-0.5)*ya3
- va*ya4 + va*ya5;
yav := (ua + va - 1.5)*ya1 - ua*ya2 +(2-ua-2*va)*ya4 + ua*ya5
+ (va - 0.5)*ya6;
zau := (ua + va - 1.5)*za1 + (2-2*ua-va)*za2 + (ua-0.5)*za3
- va*za4 + va*za5;
zav := (ua + va - 1.5)*za1 - ua*za2 +(2-ua-2*va)*za4 + ua*za5
+ (va - 0.5)*za6;
xbu := (ub + vb - 1.5)*xb1 + (2-2*ub-vb)*xb2 + (ub-0.5)*xb3
- vb*xb4 + vb*xb5;
xbv := (ub + vb - 1.5)*xb1 - ub*xb2 +(2-ub-2*vb)*xb4 + ub*xb5
+ (vb - 0.5)*xb6;
ybu := (ub + vb - 1.5)*yb1 + (2-2*ub-vb)*yb2 + (ub-0.5)*yb3
- vb*yb4 + vb*yb5;
ybv := (ub + vb - 1.5)*yb1 - ub*yb2 +(2-ub-2*vb)*yb4 + ub*yb5
+ (vb - 0.5)*yb6;
zbu := (ub + vb - 1.5)*zb1 + (2-2*ub-vb)*zb2 + (ub-0.5)*zb3
- vb*zb4 + vb*zb5;
zbv := (ub + vb - 1.5)*zb1 - ub*zb2 +(2-ub-2*vb)*zb4 + ub*zb5
+ (vb - 0.5)*zb6;
uagrad := 2*dx*xau + 2*dy*yau + 2*dz*zau;
vagrad := 2*dx*xav + 2*dy*yav + 2*dz*zav;
ubgrad := -(2*dx*xbu + 2*dy*ybu + 2*dz*zbu);
vbgrad := -(2*dx*xbv + 2*dy*ybv + 2*dz*zbv);
// find multiple of gradient; factor of 2 due to dist^2
tt := 2*dd/(uagrad*uagrad+vagrad*vagrad+ubgrad*ubgrad+vbgrad*vbgrad);
// clamp to triangle boundaries if necessary
// actually, clamp short of bdry so don't have to worry
// about being on boundary.
if ( ua - tt*uagrad < eps ) then tt := (-eps+ua)/uagrad;
if ( va - tt*vagrad < eps ) then tt := (-eps+va)/vagrad;
if ( ua - tt*uagrad + va - tt*vagrad > 2 - eps )
then tt := (-2 + eps + ua + va)/(uagrad + vagrad);
if ( ub - tt*ubgrad < eps ) then tt := (-eps+ub)/ubgrad;
if ( vb - tt*vbgrad < eps ) then tt := (-eps+vb)/vbgrad;
if ( ub - tt*ubgrad + vb - tt*vbgrad > 2 - eps )
then tt := -(2 - eps - ub - vb)/(ubgrad + vbgrad);
ua := ua - tt*uagrad;
va := va - tt*vagrad;
ub := ub - tt*ubgrad;
vb := vb - tt*vbgrad;
eps := eps/5;
};
if ( dd < tiny )
then printf "Facets %d and %d intersect at (%g,%g,%g).\n",xa,ya,za;
}
}
}
evolver-2.30c.dfsg/fe/dxf.cmd 0000755 0001753 0001753 00000002623 11410765113 016274 0 ustar hazelsct hazelsct // dfx.cmd
// Evolver command to produce AutoCad DXF files
// Programmer: Ken Brakke, brakke@susqu.edu, http://www.susqu.edu/brakke
// References:
// http://en.wikipedia.org/wiki/AutoCAD_DXF
// http://images.autodesk.com/adsk/files/acad_dxf.pdf
// Usage:
// dxf >>> "filename.dxf"
define dxf_colors integer[16];
dxf_colors[1] := 5 // blue
dxf_colors[2] := 3 // green
dxf_colors[3] := 4 // cyan
dxf_colors[4] := 10 // red
dxf_colors[5] := 6 // magenta
dxf_colors[6] := 1 // brown
dxf_colors[7] := 9 // lightgray
dxf_colors[8] := 8 // darkgray
dxf_colors[9] := 8 // lightblue
dxf_colors[10] := 3 // lightgreen
dxf_colors[11] := 4 // lightcyan
dxf_colors[12] := 14 // lightred
dxf_colors[13] := 6 // lightmagenta
dxf_colors[14] := 2 // yellow
dxf_colors[15] := 7 // white
dxf := {
printf " 0\nSECTION\n 2\nENTITIES\n";
foreach facet ff do
{ printf " 0\n3DFACE\n 8\n0main\n";
printf " 10\n%8.6f\n 20\n%8.6f\n 30\n%8.6f\n",ff.vertex[1].x,
ff.vertex[1].y,ff.vertex[1].z;
printf " 11\n%8.6f\n 21\n%8.6f\n 31\n%8.6f\n",ff.vertex[2].x,
ff.vertex[2].y,ff.vertex[2].z;
printf " 12\n%8.6f\n 22\n%8.6f\n 32\n%8.6f\n",ff.vertex[3].x,
ff.vertex[3].y,ff.vertex[3].z;
printf " 13\n%8.6f\n 23\n%8.6f\n 33\n%8.6f\n",ff.vertex[3].x,
ff.vertex[3].y,ff.vertex[3].z;
// try color
printf " 62\n%3d\n",dxf_colors[ff.color];
};
printf " 0\nENDSEC\n 0\nEOF\n";
}
evolver-2.30c.dfsg/fe/quadm.fe 0000644 0001753 0001753 00000001256 11410765113 016447 0 ustar hazelsct hazelsct // quadm.fe
// quadrilateral boundary wire
// test of metric
INTEGRAL_ORDER 7
METRIC
/*
1+4*x1^2 4*x1*x2 2*x1
4*x1*x2 1+4*x2^2 2*x2
2*x1 2*x2 1
*/
1 0 0
0 1 0
0 0 1
constraint 1
formula: x1 = 0
constraint 2
formula: x1 = 1
constraint 3
formula: x2 = 0
constraint 4
formula: x2 = 1
constraint 5
formula: x1^2 + x2^2 + x3 = 0
vertices
1 0 0 0 fixed
2 1 0 -1 fixed
3 1 1 -2 fixed
4 0 1 -1 fixed
edges
1 1 2 fixed constraints 3,5
2 2 3 fixed constraints 2,5
3 3 4 fixed constraints 4,5
4 4 1 fixed constraints 1,5
5 2 4
faces
1 1 5 4
2 2 3 -5
read
// Typical evolution
gogo := { r; g 12; U; r; g 12; r; g 12; r; g 20; }
evolver-2.30c.dfsg/fe/crystal.fe 0000644 0001753 0001753 00000001702 11410765113 017015 0 ustar hazelsct hazelsct // crystal.fe
// Evolver data for cube of prescribed volume with
// crystalline surface energy. Evolves into an octahedron.
Wulff "octa.wlf" // Wulff vectors for octahedral crystal
vertices
1 0.0 0.0 0.0
2 1.0 0.0 0.0
3 1.0 1.0 0.0
4 0.0 1.0 0.0
5 0.0 0.0 1.0
6 1.0 0.0 1.0
7 1.0 1.0 1.0
8 0.0 1.0 1.0
9 0.0 0.0 0.5
10 1.0 0.0 0.5
11 1.0 1.0 0.5
12 0.0 1.0 0.5
edges /* given by endpoints and attribute */
1 1 2
2 2 3
3 3 4
4 4 1
5 5 6
6 6 7
7 7 8
8 8 5
9 1 9
10 2 10
11 3 11
12 4 12
13 9 5
14 10 6
15 11 7
16 12 8
17 9 10
18 10 11
19 11 12
20 12 9
faces /* given by oriented edge loop */
1 1 10 -17 -9
2 2 11 -18 -10
3 3 12 -19 -11
4 4 9 -20 -12
5 5 6 7 8
6 -4 -3 -2 -1
7 17 14 -5 -13
8 18 15 -6 -14
9 19 16 -7 -15
10 20 13 -8 -16
bodies /* one body, defined by its oriented faces */
1 1 2 3 4 5 6 7 8 9 10 volume 1
read
// Sample evolution
gogo := { g 10; }
evolver-2.30c.dfsg/fe/rib.cmd 0000755 0001753 0001753 00000006447 11410765113 016277 0 ustar hazelsct hazelsct // rib.cmd
// Surface Evolver command to write RenderMan RIB file for surface
// Usage: rib >>> "filename.rib"
// This version does facets only, on a light blue background.
// Viewpoint is the same as 's' command. Orthogonal projection.
// Programmer: Ken Brakke, brakke@susqu.edu, http://www.susqu.edu/brakke
rib := {
printf"##RenderMan RIB-Structure 1.0\n";
printf "version 3.03\n";
printf "\n";
printf "Option \"searchpath\" \"shader\" [\".:../shaders:&\"]\n";
printf "Display \"%s.tif\" \"file\" \"rgba\"\n",datafilename;
printf "Format 512 512 -1\n";
printf "PixelSamples 1 1\n";
printf "Orientation \"rh\"\n";
printf "Clipping 0.1 10.0\n";
printf "\n";
printf "WorldBegin\n";
printf "\n";
printf "Surface \"constant\"\n"; /* blue background */
printf "Color [ 0.3 0.8 1.0 ]\n";
printf "Polygon \"P\" [ 1 1 9 -1 1 9 -1 -1 9 1 -1 9]\n";
printf "\n";
printf "Translate 0 0 5 \n";
printf "Rotate 240 1 1 1 \n";
printf "Scale -1 1 1 \n";
printf "Scale .66667 .66667 .66667 \n";
printf "ConcatTransform [ %f %f %f %f\n",
view_matrix[1][1],view_matrix[2][1],view_matrix[3][1],view_matrix[4][1];
printf " %f %f %f %f\n",
view_matrix[1][2],view_matrix[2][2],view_matrix[3][2],view_matrix[4][2];
printf " %f %f %f %f\n",
view_matrix[1][3],view_matrix[2][3],view_matrix[3][3],view_matrix[4][3];
printf " %f %f %f %f ]\n",
view_matrix[1][4],view_matrix[2][4],view_matrix[3][4],view_matrix[4][4];
printf "LightSource \"ambientlight\" 1 \"intensity\" 0.30\n";
printf "LightSource \"distantlight\" 1 \"from\" [1 0 1] \"to\" [0 0 0] \"intensity\" 0.7\n";
printf "\n";
printf "AttributeBegin\n";
printf " Surface \"constant\"\n";
foreach facet ff do {
if ( ff.color == CLEAR ) then continue;
if ( ff.color == WHITE ) then printf " Color [ 1.0 1.0 1.0 ]\n"
else if ( ff.color == WHITE ) then printf " Color [ 1.0 1.0 1.0 ]\n"
else if ( ff.color == BLACK ) then printf " Color [ 0.0 0.0 0.0 ]\n"
else if ( ff.color == BLUE ) then printf " Color [ 0.0 0.0 1. ]\n"
else if ( ff.color == GREEN ) then printf " Color [ 0.0 1. 0.0 ]\n"
else if ( ff.color == CYAN ) then printf " Color [ 0.0 1. 1. ]\n"
else if ( ff.color == RED ) then printf " Color [ 1. 0.0 0.0 ]\n"
else if ( ff.color == MAGENTA ) then printf " Color [ 1. 0.0 1. ]\n"
else if ( ff.color == BROWN ) then printf " Color [ 1. 0.5 0. ]\n"
else if ( ff.color == LIGHTGRAY ) then printf " Color [ .6 .6 .6 ]\n"
else if ( ff.color == DARKGRAY ) then printf " Color [ .3 .3 .3 ]\n"
else if ( ff.color == LIGHTBLUE ) then printf " Color [ .5 .5 1. ]\n"
else if ( ff.color == LIGHTGREEN ) then printf " Color [ .5 1. .5 ]\n"
else if ( ff.color == LIGHTCYAN ) then printf " Color [ .5 1. 1. ]\n"
else if ( ff.color == LIGHTRED ) then printf " Color [ 1. .5 .5 ]\n"
else if ( ff.color == LIGHTMAGENTA ) then printf " Color [ 1. .5 1. ]\n"
else if ( ff.color == YELLOW ) then printf " Color [ 1. 1. .0 ]\n";
printf " Polygon \"P\" [ %f %f %f %f %f %f %f %f %f ]\n",
ff.vertex[1].x,ff.vertex[1].y,ff.vertex[1].z,
ff.vertex[2].x,ff.vertex[2].y,ff.vertex[2].z,
ff.vertex[3].x,ff.vertex[3].y,ff.vertex[3].z;
};
printf "AttributeEnd\n";
printf "\n";
printf "WorldEnd\n";
}
evolver-2.30c.dfsg/fe/intersec.cmd 0000755 0001753 0001753 00000004130 11410765113 017322 0 ustar hazelsct hazelsct // intersec.cmd
// Evolver command to detect intersection of linear edges and facets.
// For each facet, finds if any edge intersects in interior.
// Usage: read "intersec.cmd"
// detect
// Output: prints ids of facets and edges that intersect.
// Notes: In quadratic model, treats edges and facets as simply linear.
// Will not work in Lagrange model.
eps := 1e-10 // tolerance for being equal to zero
detect := {
local ax,ay,az,bx,by,bz,cx,cy,cz,acx,bcx,px,py,pz,qx,qy,qz,qpx,qcx;
local denom,lambda,mu,sigma;
local acy,acz,bcy,bcz,qpy,qpz,qcy,qcz;
if lagrange then
{ printf "intersect.cmd will not work in Lagrange model.\n";return;};
foreach facet ff do
{ ax := ff.vertex[1].x;
ay := ff.vertex[1].y;
az := ff.vertex[1].z;
bx := ff.vertex[2].x;
by := ff.vertex[2].y;
bz := ff.vertex[2].z;
cx := ff.vertex[3].x;
cy := ff.vertex[3].y;
cz := ff.vertex[3].z;
acx := ax-cx; acy := ay-cy; acz := az- cz;
bcx := bx-cx; bcy := by-cy; bcz := bz- cz;
foreach edge ee do
{ px := ee.vertex[1].x;
py := ee.vertex[1].y;
pz := ee.vertex[1].z;
qx := ee.vertex[2].x;
qy := ee.vertex[2].y;
qz := ee.vertex[2].z;
qpx := qx-px; qpy := qy-py; qpz := qz-pz;
qcx := qx-cx; qcy := qy-cy; qcz := qz-cz;
denom := qpx*(acy*bcz-acz*bcy) - qpy*(acx*bcz-acz*bcx)
+ qpz*(acx*bcy-acy*bcx);
if ( abs(denom) < eps ) then continue;
lambda := (qpx*(qcy*bcz-qcz*bcy) - qpy*(qcx*bcz-qcz*bcx)
+ qpz*(qcx*bcy-qcy*bcx))/denom;
if ( lambda <= eps ) then continue;
mu := (qpx*(acy*qcz-acz*qcy) - qpy*(acx*qcz-acz*qcx)
+ qpz*(acx*qcy-acy*qcx))/denom;
if ( mu <= eps ) then continue;
if ( lambda + mu > 1-eps ) then continue;
sigma := (qcx*(acy*bcz-acz*bcy) - qcy*(acx*bcz-acz*bcx)
+ qcz*(acx*bcy-acy*bcx))/denom;
if ( (sigma <= eps) or (sigma > 1-eps) ) then continue;
// now have intersection
printf "Facet %g and edge %g intersect.\n",ff.id,ee.id;
}
}
}
evolver-2.30c.dfsg/fe/povray.cmd 0000755 0001753 0001753 00000010663 11410765113 017036 0 ustar hazelsct hazelsct // povray.cmd
// Surface Evolver command for producing POV-Ray input file.
// Usage:
// Use the "show edge where ..." command to declare which
// edges are to be depicted as thin cylinders.
// Set "edge_radius" to desired radius of edge cylinders.
// Run "povray" and redirect to desired file, e.g.
// Enter command: povray >>> "something.pov"
// Programmer: Ken Brakke, brakke@susqu.edu, http://www.susqu.edu/brakke
edge_radius := 0.003; // adjust this for desired radius of edge cylinders
povray := {
printf "// %s in POV-Ray format.\n\n",datafilename;
printf "light_source { <0,0,300> color rgb <1,1,1> }\n";
printf "light_source { <100,0,0> color rgb <1,1,1> }\n";
printf "camera { location <12,0,0> sky <0,0,1> // right handed \n";
printf " up <0,0,1> right <1.3,0,0> look_at <0,0,0> angle 15 }\n";
printf "background { color <0.3,0.8,1.0> } // light blue\n\n";
printf "// Textures corresponding to Evolver colors\n\n";
printf "#declare t_black = texture { pigment { rgb <0.0,0.0,0.0> }}\n";
printf "#declare t_blue = texture { pigment { rgb <0.0,0.0,1.,> }}\n";
printf "#declare t_green = texture { pigment { rgb <0.0,1.,0.0,> }}\n";
printf "#declare t_cyan = texture { pigment { rgb <0.0,1.,1.,> }}\n";
printf "#declare t_red = texture { pigment { rgb <1.,0.0,0.0,> }}\n";
printf "#declare t_magenta = texture { pigment { rgb <1.,0.0,1.,> }}\n";
printf "#declare t_brown = texture { pigment { rgb <1.,0.5,0.,> }}\n";
printf "#declare t_lightgray = texture { pigment { rgb <.6,.6,.6,> }}\n";
printf "#declare t_darkgray = texture { pigment { rgb <.3,.3,.3,> }}\n";
printf "#declare t_lightblue = texture { pigment { rgb <.3,.8,1.,> }}\n";
printf "#declare t_lightgreen = texture { pigment { rgb <.5,1.,.5,> }}\n";
printf "#declare t_lightcyan = texture { pigment { rgb <.5,1.,1.,> }}\n";
printf "#declare t_lightred = texture { pigment { rgb <1.,.5,.5,> }}\n";
printf "#declare t_lightmagenta = texture { pigment { rgb <1.,.5,1.,> }}\n";
printf "#declare t_yellow = texture { pigment { rgb <1.,1.,.0,> }}\n";
printf "#declare t_white = texture { pigment { rgb <1.,1.,1.,> }}\n";
printf "\n//One overall object.\n";
printf "union {\n";
printf "// All facets in one big mesh object for efficiency.\n";
printf " mesh { \n";
foreach facet ff do {
printf " triangle { <%f,%f,%f>,<%f,%f,%f>,<%f,%f,%f> texture {",
ff.vertex[1].x,ff.vertex[1].y,ff.vertex[1].z,
ff.vertex[2].x,ff.vertex[2].y,ff.vertex[2].z,
ff.vertex[3].x,ff.vertex[3].y,ff.vertex[3].z;
if ( ff.color == white ) then printf " t_white "
else if ( ff.color == black ) then printf " t_black "
else if ( ff.color == blue) then printf " t_blue "
else if ( ff.color == green ) then printf " t_green "
else if ( ff.color == cyan ) then printf " t_cyan "
else if ( ff.color == red ) then printf " t_red "
else if ( ff.color == magenta ) then printf " t_magenta "
else if ( ff.color == brown ) then printf " t_brown "
else if ( ff.color == lightgray ) then printf " t_lightgray "
else if ( ff.color == darkgray ) then printf " t_darkgray "
else if ( ff.color == lightblue ) then printf " t_lightblue "
else if ( ff.color == lightgreen ) then printf " t_lightgreen "
else if ( ff.color == lightcyan ) then printf " t_lightcyan "
else if ( ff.color == lightred ) then printf " t_lightred "
else if ( ff.color == lightmagenta ) then printf " t_lightmagenta "
else if ( ff.color == yellow ) then printf " t_yellow ";
printf " } }\n";
};
printf " } // end of mesh object\n";
// Do desired edges
printf "#declare edge_radius = %f;\n",edge_radius;
foreach edge ee where ee.show do
{ printf "cylinder { <%f,%f,%f>,<%f,%f,%f> edge_radius texture { t_black } }\n",
ee.vertex[1].x,ee.vertex[1].y,ee.vertex[1].z,
ee.vertex[2].x,ee.vertex[2].y,ee.vertex[2].z;
};
// Windup
printf "// overall viewing transformation\n";
printf " matrix < %f,%f,%f,\n",
view_matrix[1][1],view_matrix[2][1],view_matrix[3][1];
printf " %f,%f,%f,\n",
view_matrix[1][2],view_matrix[2][2],view_matrix[3][2];
printf " %f,%f,%f,\n",
view_matrix[1][3],view_matrix[2][3],view_matrix[3][3];
printf " %f,%f,%f>\n",
view_matrix[1][4],view_matrix[2][4],view_matrix[3][4];
printf " } // end of all objects\n";
}
evolver-2.30c.dfsg/fe/xray.cmd 0000755 0001753 0001753 00000011144 11410765113 016474 0 ustar hazelsct hazelsct // xray.cmd
// Produces xray image of a 3D wet foam. Calculates liquid content on
// grid of probe lines. Plateau borders are detected as bounded by
// facets with less than 2/3 of the maximum facet tension.
// Outputs a PostScript file to stdout with a grid of grayscale pixels.
// Usage: set xgridsize and ygridsize to the desired resolution,
// i.e. pixels across and down and give the command
// xray >>> "filename.ps"
// The xray command will calculate the bounding box of the surface itself.
// Works in torus or non-torus mode. In torus mode, everything will
// automatically be wrapped back to the unit cell, so you don't have
// to worry about that.
// Programmer: Ken Brakke, brakke@susqu.edu, http://www.susqu.edu/brakke
xgridsize := 100 // xgridsize x ygridsize grid
ygridsize := 100
xray := {
local xx,yy,jitterx,jittery,minx,miny,maxx,maxy,tension_cutoff;
local dx,dy,ax,ay,az,bx,by,bz,cx,cy,cz,hix,hiy,lox,loy,maxi,maxj;
local mini,minj,fsign,xyarea,ii,jj,area1,area2,area3,maxr,xpts,ypts;
define results real[xgridsize][ygridsize];
for ( xx := 1 ; xx <= xgridsize ; xx += 1 )
for ( yy := 1 ; yy <= ygridsize ; yy += 1 )
results[xx][yy] := 0.0; // clean out old results
// random offsets to prevent edge effects */
jitterx := 0.5213414312341;
jittery := 0.4934129768877;
/* box to map results to */
if torus then
{ // assumes orthogonal fundamental region
minx := 0;
miny := 0;
maxx := torus_periods[1][1];
maxy := torus_periods[2][2];
tension_cutoff := max(facet,tension)*2/3; // do only Plateau borders
}
else
{ minx := min(vertex,x);
maxx := max(vertex,x);
miny := min(vertex,y);
maxy := max(vertex,y);
tension_cutoff := 100000; // do all facets
};
dx := (maxx-minx)/xgridsize;
dy := (maxy-miny)/ygridsize;
foreach facet ff where tension < tension_cutoff do
{ ax := ff.vertex[1].x;
ay := ff.vertex[1].y;
az := ff.vertex[1].z;
bx := ax + ff.edge[1].x; // let Evolver take care of unwrapping
by := ay + ff.edge[1].y;
bz := az + ff.edge[1].z;
cx := bx + ff.edge[2].x; // let Evolver take care of unwrapping
cy := by + ff.edge[2].y;
cz := bz + ff.edge[2].z;
// get bounding box to find possible grid points
hix := (ax > bx) ? (ax > cx ? ax : cx) : (bx > cx ? bx : cx);
hiy := (ay > by) ? (ay > cy ? ay : cy) : (by > cy ? by : cy);
lox := (ax < bx) ? (ax < cx ? ax : cx) : (bx < cx ? bx : cx);
loy := (ay < by) ? (ay < cy ? ay : cy) : (by < cy ? by : cy);
// compact to integers
maxi := floor(hix/dx-jitterx);
maxj := floor(hiy/dy-jittery);
mini := ceil(lox/dx-jitterx);
minj := ceil(loy/dy-jittery);
// loop among possible values
fsign := ff.z > 0 ? 1 : -1;
xyarea := 2*abs(ff.z);
for ( ii := mini ; ii <= maxi ; ii += 1 )
for ( jj := minj ; jj <= maxj ; jj += 1 )
{ // test inclusion
xx := ii*dx + dx*jitterx; yy := jj*dy + dy*jittery;
area1 := fsign*((ax-xx)*(by-yy) - (bx-xx)*(ay-yy));
area2 := fsign*((bx-xx)*(cy-yy) - (cx-xx)*(by-yy));
area3 := fsign*((cx-xx)*(ay-yy) - (ax-xx)*(cy-yy));
if ( (area1 > 0) and (area2 > 0) and (area3 > 0) ) then
{ results[(ii imod xgridsize)+1][(jj imod ygridsize)+1] +=
fsign*(area1*cz + area2*az + area3*bz)/xyarea;
}
}
};
if ( torus ) then
{ // correct results for wrap in z
for ( ii := 1 ; ii <= xgridsize ; ii += 1 )
for ( jj := 1 ; jj <= ygridsize ; jj += 1 )
results[ii][jj] := results[ii][jj] mod torus_periods[3][3];
};
// map to range 0,1
maxr := 0;
for ( ii := 1 ; ii <= xgridsize ; ii += 1 )
for ( jj := 1 ; jj <= ygridsize ; jj += 1 )
if results[ii][jj] > maxr then maxr := results[ii][jj];
if maxr > 0 then
for ( ii := 1 ; ii <= xgridsize ; ii += 1 )
for ( jj := 1 ; jj <= ygridsize ; jj += 1 )
results[ii][jj] /= maxr;
/* output results in postscript format, making low density white */
xpts := 500; ypts := 500; // point size of image
// using kludges to get %% stuff to print right on Windows and Unix
printf "%!"; printf"PS-Adobe-3.0 EPSF-3.0\n";
printf "%%"; printf"BoundingBox: 0 0 %d %d\n",xpts,ypts;
printf "%%"; printf"Creator: Surface Evolver xray.cmd\n";
printf "%%"; printf"EndComments\n\n";
printf "%f %f scale\n",xpts/xgridsize,ypts/ygridsize;
printf "/px { newpath setgray moveto 1 0 rlineto 0 1 rlineto -1 0 rlineto closepath fill} def\n";
for ( ii := 0 ; ii < xgridsize ; ii += 1 )
for ( jj := 0 ; jj < ygridsize ; jj += 1 )
{ printf "%f %f %f px\n",ii,jj,(1-results[ii+1][jj+1]);
};
printf "\nshowpage\n";
printf "\n%%"; printf"EOF\n";
}
evolver-2.30c.dfsg/fe/wetfoam2.cmd 0000755 0001753 0001753 00000062746 11410765113 017253 0 ustar hazelsct hazelsct // wetfoam2.cmd
// Evolver command to convert dry foam to wet foam.
// Dry foam assumptions:
// In torus domain (so no awkward boundary conditions)
// Only one high valence edge per facet (will refine if finds more )
// Facet tension assumed to be uniformly 1.
// Usage: Set "spread" to relative size of border (default 0.2), then
// run wetfoam with output redirected to desired file, e.g.
// Enter command: wetfoam >>> "wetfile.fe"
// The resulting file has Plateau border body, whose number is recorded
// in the variable border_body.
// This file replaces wetfoam.cmd, which is now obsolete.
// Programmer: Ken Brakke, brakke@susqu.edu, http://www.susqu.edu/brakke
/* Parameter for initial size of Plateau borders */
/* Note this is relative to the size of facets, not absolute. */
spread := .2
// Other global variables used internally here
ccount := 0
voffset := 0
wrapnum := 0;
border_body := 0;
init_attributes := {
// some useful attributes, all as dimensioned so can be shrunk to zero size
// when done with them.
define vertex attribute hivalence integer[1]; // number of high-valence edges
define facet attribute corners integer[3]; // which "corner" each vertex
// belongs to
define facet attribute newedge integer[1]; // pulled-out edge
define facet attribute corneredge1 integer[3];// new edge forward from corner
define facet attribute corneredge2 integer[3];// new edge backward from corner
define facet attribute didflag1 integer[3];// whether put vertex face here
define facet attribute didflag2 integer[3];// whether put vertex face here
define facet attribute diagedge integer[1]; // diagonal across rectangle
}
shrink_attributes := {
// make storage small so to not pollute memory of original or new file.
define vertex attribute hivalence integer[0];
define facet attribute corners integer[0];
define facet attribute newedge integer[0];
define facet attribute corneredge1 integer[0];
define facet attribute corneredge2 integer[0];
define facet attribute didflag1 integer[0];
define facet attribute didflag2 integer[0];
define facet attribute diagedge integer[0];
// and a few arrays while we are at it
define cornerx real[0];
define cornery real[0];
define cornerz real[0];
define cornern integer[0];
define borderbody integer[0];
}
/* tests and preliminaries */
vertest := { foreach vertex vv do
vv.hivalence[1] := sum(vv.edge where valence >= 3,1);
}
facettest := { local triple;
foreach facet ff do
{ triple := sum(ff.edge where valence >= 3, 1);
if ( triple >= 2 ) then
{ refine ff;
}
}
}
wettests := { vertest; facettest; }
/* enumerate and consolidate facet corners */
/* corner number of 0 means not adjacent to hi-valence vertex */
do_corners := {
local inx;
/* enumerate */
ccount := 1;
foreach facet ff do
{
inx := 1;
foreach ff.vertex vv do
{ if vv.hivalence[1] > 0 then
{ ff.corners[inx] := ccount;
ccount += 1;
};
inx += 1;
};
};
/* consolidate */
local changes;
do
{ changes := 0;
foreach edge ee do
{ if ee.valence != 2 then continue;
local ffid; local fffid; local knx;
ffid := ee.facet[1].id;
fffid := ee.facet[2].id;
inx := 1;
foreach facet[ffid].vertex vv do
{ if vv.id != ee.vertex[1].id && vv.id != ee.vertex[2].id then
{ inx += 1; continue; };
knx := 1;
foreach facet[fffid].vertex vvv do
{ if vv.id == vvv.id then
{ if facet[ffid].corners[inx] == facet[fffid].corners[knx] then
break;
if facet[ffid].corners[inx] < facet[fffid].corners[knx] then
facet[fffid].corners[knx] := facet[ffid].corners[inx]
else facet[ffid].corners[inx] := facet[fffid].corners[knx];
changes += 1;
break;
};
knx += 1;
};
inx += 1;
}
}
} while changes;
/* array to hold info on corner vertices */
define cornerx real[ccount];
define cornery real[ccount];
define cornerz real[ccount];
define cornern integer[ccount]; // number of facets in corner
inx := 1; while inx <= ccount do
{ cornern[inx] := 0; cornerx[inx] := 0; cornery[inx] := 0;
cornerz[inx] := 0; inx += 1;
};
foreach facet ff do
{ inx := 1;
local ffid;
ffid := ff.id; /* want positive orientation */
while inx <= 3 do
{ if ff.corners[inx] != 0 then
{ cornern[ff.corners[inx]] += 1;
cornerx[ff.corners[inx]] +=
spread*facet[ffid].edge[inx].x + 2*facet[ffid].vertex[inx].x
- spread*facet[ffid].edge[inx==1 ? 3 : inx-1].x;
cornery[ff.corners[inx]] +=
spread*facet[ffid].edge[inx].y + 2*facet[ffid].vertex[inx].y
- spread*facet[ffid].edge[inx==1 ? 3 : inx-1].y;
cornerz[ff.corners[inx]] +=
spread*facet[ffid].edge[inx].z + 2*facet[ffid].vertex[inx].z
- spread*facet[ffid].edge[inx==1 ? 3 : inx-1].z;
};
inx += 1;
};
};
local kk;
kk := 1;
while kk <= ccount do
{ if cornern[kk] > 0 then
{ cornerx[kk] /= 2*cornern[kk];
cornery[kk] /= 2*cornern[kk];
cornerz[kk] /= 2*cornern[kk];
};
kk += 1;
};
} /* end do_corners */
/* print vertex list */
wetverts := {
voffset := max(vertex,id)+1; /* start of new vertices */
printf "\nvertices\n";
foreach vertex vv do
if ( vv.hivalence[1] < 1 ) then
printf "%d %g %g %g\n",vv.id, vv.x,vv.y,vv.z;
local kk;
kk := 1;
while kk <= ccount do
{ if cornern[kk] > 0 then
{ printf "%d %g %g %g\n",kk+voffset,
cornerx[kk],cornery[kk],cornerz[kk];
};
kk += 1;
}
} /* end wetverts */
/* convert numerical torus wrap to string and print; called by wetedges */
/* incoming argument: wrapnum */
wrapconvert := { local ww;
ww := floor(1e-6 + (wrapnum % 64));
if ( ww == 0 ) then printf " *"
else if ( ww == 1 ) then printf " +"
else printf " -";
ww := floor(1e-6 + (floor(1e-6+wrapnum/64) % 64) );
if ( ww == 0 ) then printf " *"
else if ( ww == 1 ) then printf " +"
else printf " -";
ww := floor(1e-6 + (floor(1e-6+wrapnum/4096) % 64) );
if ( ww == 0 ) then printf " *"
else if ( ww == 1 ) then printf " +"
else printf " -";
}
/* print edge list */
wetedges := { local ecounter;
local eeid; local first_corner; local corner;
local prevff; local previnx; local firstff;
local firstinx; local prevcorner;
local ffid; local inx;
local ffid2; local eeid2;
ecounter := max(edge,id)+1; /* start of new edges */
printf "\nedges\n";
/* first, old edges that we keep */
foreach edge ee where valence == 2 do
{ printf "%d ", ee.id;
wrapnum := ee.wrap;
foreach ee.vertex vv do
{ if ( vv.hivalence[1] > 0 ) then
{ /* find proper pull-out vertex */
local ffid;
ffid := ee.facet[1].id;
inx := 1;
while inx <= 3 do
{ if facet[ffid].vertex[inx].id == vv.id then
{ printf "%d ",facet[ffid].corners[inx]+voffset;
break;
};
inx += 1;
}
}
else printf "%d ",vv.id;
};
if ( torus ) then wrapconvert;
printf "\n";
};
foreach edge ee where valence >= 3 do
{ local tail1; local tail2; local tail3;
local head1; local head2; local head3;
local vv1; local inx;
local headv; local tailv; local ffid;
local vv2;
tail1 := 0; tail2 := 0; tail3 := 0;
head1 := 0; head2 := 0; head3 := 0;
wrapnum := ee.wrap;
/* assemble data about new vertices */
vv1 := ee.vertex[1].id; vv2 := ee.vertex[2].id;
foreach ee.facet ff do
{ /* new edge between facet corners */
ffid := ff.id; /* want positive orientation of facet */
inx := 1;
foreach facet[ffid].vertex vv do
{ if vv.id == vv1 then tailv := ff.corners[inx]+voffset;
if vv.id == vv2 then headv := ff.corners[inx]+voffset;
inx += 1;
};
ff.newedge[1] := ecounter;
ff.diagedge[1] := ecounter+3;
printf "%d %d %d ",ecounter,tailv,headv;
if torus then wrapconvert;
printf "/* from edge %d */ ",ee.id;
printf "\n";
tail1 := tail2; tail2 := tail3; tail3 := tailv;
head1 := head2; head2 := head3; head3 := headv;
ecounter += 1;
};
printf "%d %d %d ",ecounter,tail1,head2;
if torus then wrapconvert;
printf "\n";
ecounter += 1;
printf "%d %d %d ",ecounter,tail2,head3;
if torus then wrapconvert;
printf "\n";
ecounter += 1;
printf "%d %d %d ",ecounter,tail3,head1;
if torus then wrapconvert;
printf "\n";
ecounter += 1;
};
/* interior points of hi-valence edges */
foreach vertex vv where vv.hivalence[1] == 2 do
{ /* find the high-valence edges first */
local ffid;
eeid := 0;
foreach vv.edge ee do
{ if ee.valence > 2 then
{ eeid2 := eeid; eeid := ee.id; }
};
first_corner := 0; corner := 0; prevff:=0; previnx:=0;
firstff := 0; firstinx := 0;
foreach edge[eeid].facet ff do
{ /* find proper corner */
prevcorner := corner;
ffid := ff.id;
inx := 1;
while inx <= 3 do
{ if facet[ffid].vertex[inx].id == vv.id then
{ corner := facet[ffid].corners[inx];
break;
};
inx += 1;
};
if ( first_corner == 0 ) then
{ first_corner := corner; prevff := ffid;
firstff := ffid; firstinx := inx;
previnx := inx;
continue;
};
/* edge from previous corner */
if torus then
printf "%d %d %d * * *\n",ecounter,prevcorner+voffset,
corner+voffset
else
printf "%d %d %d\n",ecounter,prevcorner+voffset,
corner+voffset;
facet[prevff].corneredge1[previnx] := ecounter;
facet[ffid].corneredge2[inx] := ecounter;
ecounter += 1;
prevff := ffid; previnx := inx;
};
if torus then
printf "%d %d %d * * *\n",ecounter,corner+voffset,
first_corner+voffset
else
printf "%d %d %d \n",ecounter,corner+voffset,
first_corner+voffset;
facet[prevff].corneredge1[previnx] := ecounter;
facet[firstff].corneredge2[firstinx] := ecounter;
ecounter += 1;
/* set corneredges on facets around the other edge */
local signum; local finx; local finx2; local inx2;
if (edge[eeid].vertex[1].id == edge[eeid2].vertex[2].id) or
(edge[eeid].vertex[2].id == edge[eeid2].vertex[1].id) then
signum := 1 // both in same direction
else signum := -1;
finx2 := 1;
foreach edge[eeid2].facet fff do
{ ffid2 := fff.id;
inx2 := 1;
while inx2 <= 3 do
{ if facet[ffid2].vertex[inx2].id == vv.id then
{ finx := 1;
foreach edge[eeid].facet ff do
{ ffid := ff.id;
inx := 1;
while inx <= 3 do
{ if facet[ffid].corners[inx] !=
facet[ffid2].corners[inx2] then
{ inx += 1; continue; };
if signum == 1 then
{ facet[ffid2].corneredge1[inx2] :=
facet[ffid].corneredge1[inx];
facet[ffid2].corneredge2[inx2] :=
facet[ffid].corneredge2[inx];
}
else // opposite directions
{ facet[ffid2].corneredge1[inx2] :=
-facet[ffid].corneredge2[inx];
facet[ffid2].corneredge2[inx2] :=
-facet[ffid].corneredge1[inx];
};
break 3;
};
inx += 1;
};
finx += 1;
};
inx2 += 1;
};
finx2 += 1;
};
}; /* end hivalence edge interior vertices */
/* ends of hi-valence edges */
foreach edge ee where valence >= 3 do
{ foreach ee.vertex vv where vv.hivalence[1] >= 3 do
{
first_corner := 0; corner := 0; prevff:=0; previnx:=0;
firstff := 0; firstinx := 0;
foreach ee.facet ff do
{ /* find proper corner */
prevcorner := corner;
ffid := ff.id;
inx := 1;
while inx <= 3 do
{ if facet[ffid].vertex[inx].id == vv.id then
{ corner := facet[ffid].corners[inx];
break;
};
inx += 1;
};
if ( first_corner == 0 ) then
{ first_corner := corner; prevff := ffid;
firstff := ffid; firstinx := inx;
previnx := inx;
continue;
};
/* edge from previous corner */
if torus then
printf "%d %d %d * * * oldedge %d\n",ecounter,
prevcorner+voffset, corner+voffset, ee.id
else
printf "%d %d %d oldedge %d\n",ecounter,
prevcorner+voffset, corner+voffset, ee.id;
facet[prevff].corneredge1[previnx] := ecounter;
facet[ffid].corneredge2[inx] := ecounter;
ecounter += 1;
prevff := ffid; previnx := inx;
};
if torus then
printf "%d %d %d * * * oldedge %d\n",ecounter,
corner+voffset, first_corner+voffset, ee.id
else
printf "%d %d %d oldedge %d\n",ecounter,
corner+voffset, first_corner+voffset, ee.id;
facet[prevff].corneredge1[previnx] := ecounter;
facet[firstff].corneredge2[firstinx] := ecounter;
ecounter += 1;
}
};
} /* end wetedges */
/* auxiliary routine to do one pulled-out face around a hi-valence vertex.
Input is ffid, signed id of starting facet,
vvid, id of vertex in question.
*/
ffid := 0; // just to declare
vvid := 0; // just to declare
fcounter := 0; // just to declare
define borderbody integer[1] // just to declare
do_one_vertex_face :=
{ local startffid; local did_fnum; local inx;
local eeid; local cinx; local cedge; local finx;
local evalence;
startffid := ffid;
did_fnum := 0;
do
{
/* find edge with head at vertex */
inx := 1;
foreach facet[ffid].edge ee do
{ if ee.vertex[2].id == vvid then
{ eeid := ee.oid; break; };
inx += 1;
};
if edge[eeid].valence >= 3 then
{
/* calculate proper corneredge */
if ffid > 0 then
cinx := inx == 3 ? 1 : inx+1
else if inx == 1 then cinx := 1
else cinx := 5-inx;
if eeid > 0 then
{ if facet[ffid].didflag1[cinx] then return ;
cedge := facet[ffid].corneredge1[cinx];
facet[ffid].didflag1[cinx] := 1;
}
else
{ if facet[ffid].didflag2[cinx] then return;
cedge := -facet[ffid].corneredge2[cinx];
facet[ffid].didflag2[cinx] := 1;
};
if did_fnum == 0 then
{ printf "%d ",fcounter;
borderbody[fcounter] := facet[ffid].backbody;
fcounter += 1;
};
did_fnum := 1;
printf "%d ",cedge;
};
/* find next facet around edge */
finx := 1; evalence := edge[eeid].valence;
foreach edge[eeid].facet fff do
{ if fff.oid == ffid then break;
finx += 1;
};
ffid := -edge[eeid].facet[finx==evalence ? 1 : finx+1].oid;
/* add edge between corners, if necessary */
} while ffid != startffid;
printf " tension 0.5 ftype vertexfacet // by old vertex %d\n",vvid;
} /* end do_one_vertex_face */
/* print face list, less triangles at nodes */
wetfaces := {
fstart := max(facet,id)+1;
fcounter := fstart;
define borderbody integer[fcounter + 40*sum(vertex,hivalence[1]>2)
+ 2*sum(edge where valence >= 3, valence)];
printf "\nfaces\n";
/* old facets, replacing triple edges with new */
foreach facet ff do
{ printf "%d ",ff.id;
foreach ff.edge ee do
{ if ( ee.valence == 2 ) then printf "%d ",ee.oid
else
printf "%d ",(ee.oid<0?-(ff.newedge[1]):ff.newedge[1])
};
printf " oldbodies %d %d ",ff.frontbody,ff.backbody;
printf " ftype oldfacet\n";
};
/* tube faces around triple lines */
foreach edge ee where valence >= 3 do
{ local evalence; local finx;
evalence := ee.valence;
finx := 1;
while finx <= evalence do
{ local ea; local diag; local inx; local eb; local ed;
local ec;
ea := ee.facet[finx].newedge[1];
ec := ee.facet[finx==evalence?1:finx+1].newedge[1];
diag := ee.facet[finx].diagedge[1];
inx := 1;
ffid := ee.facet[finx].id;
while inx <= 3 do
{ if facet[ffid].vertex[inx].id == ee.vertex[1].id then
eb := facet[ffid].corneredge1[inx];
if facet[ffid].vertex[inx].id == ee.vertex[2].id then
ed := facet[ffid].corneredge1[inx];
inx += 1;
};
printf "%d %d %d %d tension 0.5 ftype tubefacet\n",
fcounter,-ea,diag,-ed;
borderbody[fcounter] := ee.facet[finx].backbody;
fcounter += 1;
printf "%d %d %d %d tension 0.5 ftype tubefacet\n",
fcounter,eb,ec,-diag;
borderbody[fcounter] := ee.facet[finx].backbody;
fcounter += 1;
finx += 1;
}
};
/* vertex faces */
printf "//vertex faces:\n";
foreach facet ff do
{ ff.didflag1[1] := 0;
ff.didflag1[2] := 0;
ff.didflag1[3] := 0;
ff.didflag2[1] := 0;
ff.didflag2[2] := 0;
ff.didflag2[3] := 0;
};
foreach vertex vv where hivalence[1] >= 3 do
{ /* try starting at each facet */
vvid := vv.id; // for parameter passing
foreach vv.facet ff do
{
ffid := ff.oid;
do_one_vertex_face;
ffid := -ff.oid;
do_one_vertex_face;
} /* end foreach facet facet */
} /* end foreach vertex */
} /* end wetfaces */
/* print body list */
/* new facets will be added to bodies at load time */
wetbodies := { printf "\nbodies \n";
local ss,nn,mm,border_volume;
ss := spread*avg(edge where valence==2,length);
border_volume := sum(edge where valence==3,length)*
ss*ss*0.8;
foreach body bod do
{ printf "%d ",bod.id,bod.target;
nn := 0;
foreach bod.facet ff do
{ printf "%d ",ff.oid;
nn += 1;
if ( nn == 10 ) then
{ printf "\\\n "; nn := 0;}
};
for ( mm := 1 ; mm < fcounter ; mm += 1 )
{ if borderbody[mm] == bod.id then
{ printf "%d ",-mm;
nn += 1;
if ( nn == 10 ) then
{ printf "\\\n "; nn := 0;}
};
};
printf " volume %g \n",bod.target;
};
/* border body can be given its facets */
border_body := max(body,id)+1;
printf "%d ",border_body;
local fnum;
for ( fnum := fstart ; fnum < fcounter ; fnum := fnum )
{ for ( nn := 1 ; (nn <= 10) and (fnum < fcounter) ; nn += 1 )
{ printf "%d ",fnum; fnum += 1; };
printf "\\\n";
};
printf " volume %g",border_volume;
printf "\n";
} /* end wetbodies */
/* commands to finish creating facets and bodies at load time */
read_section := {
printf "\nread\n\n";
printf "recalc\n";
printf "set body target volume // so volumes don't exceed torus volume\n";
printf "border_body := %d\n",border_body;
}
wetfoam := {
// applicability tests
if space_dimension != 3 then
{ errprintf "wetfoam only works in space dimension 3.\n"; return; };
if surface_dimension != 2 then
{ errprintf "wetfoam only works for surface dimension 2.\n";
return;
};
// if !torus then
// { errprintf "wetfoam only works for torus domain.\n"; return; };
if lagrange_order != 1 then
{ errprintf "wetfoam only works for linear model.\n"; return; };
// minimize arrays to avoid datafile pollution
define cornerx real[1];
define cornery real[1];
define cornerz real[1];
define cornern integer[1]; // number of facets in corner
shrink_attributes;
list topinfo;
init_attributes;
wettests;
printf "\ndefine edge attribute oldedge integer\n\n";
printf "\ndefine facet attribute oldbodies integer[2]\n\n";
printf "\ndefine facet attribute ftype integer\n";
printf "parameter oldfacet = 1 // original facet\n";
printf "parameter tubefacet = 2 // new facet along tube\n";
printf "parameter vertexfacet = 3 // new facet around vertex\n\n";
do_corners;
wetverts;
wetedges;
wetfaces;
wetbodies;
read_section;
shrink_attributes;
}
// To user: run wetfoam with output redirected to desired file, i.e.
// Enter command: wetfoam >>> "wetfile.fe"
evolver-2.30c.dfsg/fe/cube.fe 0000644 0001753 0001753 00000002312 11410765113 016250 0 ustar hazelsct hazelsct // cube.fe
// Evolver data for cube of prescribed volume.
vertices
1 0.0 0.0 0.0
2 1.0 0.0 0.0
3 1.0 1.0 0.0
4 0.0 1.0 0.0
5 0.0 0.0 1.0
6 1.0 0.0 1.0
7 1.0 1.0 1.0
8 0.0 1.0 1.0
edges /* given by endpoints and attribute */
1 1 2
2 2 3
3 3 4
4 4 1
5 5 6
6 6 7
7 7 8
8 8 5
9 1 5
10 2 6
11 3 7
12 4 8
faces /* given by oriented edge loop */
1 1 10 -5 -9
2 2 11 -6 -10
3 3 12 -7 -11
4 4 9 -8 -12
5 5 6 7 8
6 -4 -3 -2 -1
bodies /* one body, defined by its oriented faces */
1 1 2 3 4 5 6 volume 1
read
// Typical evolution to sphere
gogo := { g 5; r; g 5; hessian; r; g 5; hessian; }
// Evolution to very high accuracy, using higher-order Lagrange elements.
// To be run on original datafile.
gogo2 := { g 5; r; g 5; hessian; r; g 5; hessian;
lagrange 2; g 5; hessian;
lagrange 4; g 5; hessian;
lagrange 6; g 5; hessian;
ideal_rad := (3*body[1].volume/4/pi)^(1/3);
printf "Area error: %g\n",total_area - 4*pi*ideal_rad^2;
printf "Vertex radius spread: %g\n",
max(vertex,sqrt((x-.5)^2+(y-.5)^2+(z-.5)^2))
- min(vertex,sqrt((x-.5)^2+(y-.5)^2+(z-.5)^2));
}
evolver-2.30c.dfsg/fe/sphere.fe 0000644 0001753 0001753 00000005121 11410765113 016621 0 ustar hazelsct hazelsct // sphere.fe
// Spherical tank partially filled with liquid with contact angle.
SYMMETRIC_CONTENT // natural for a sphere
parameter rad = 1.00 // sphere radius
parameter angle = 45 // contact angle, in degrees
// cosine of contact angle
#define WALLT cos(angle*pi/180)
// density of body
#define RHO 1.0
// Various expressions used in constraints
#define wstuff (rad^2*z/(x^2 + y^2)/sqrt(x^2+y^2+z^2))
#define gstuff (G*RHO/8*rad^4*z^4/(x^2 + y^2)*(x^2+y^2+z^2)^2)
#define gapstuff (G*RHO*rad^4/8*z^2/(x^2+y^2+z^2)^2)
constraint 1 convex // the sphere, as wall for liquid
formula: sqrt(x^2 + y^2 + z^2) = rad
energy:
e1: WALLT*wstuff*y - gstuff*y + G*RHO/8*y*z^2 - gapstuff*y
e2: -WALLT*wstuff*x + gstuff*x - G*RHO/8*x*z^2 + gapstuff*x
e3: 0
content:
c1: -rad*wstuff*y/3
c2: rad*wstuff*x/3
c3: 0
constraint 2 // the sphere, for display only
formula: sqrt(x^2 + y^2 + z^2) = rad
vertices:
1 rad 0 0 constraint 1
2 0 rad 0 constraint 1
3 -rad 0 0 constraint 1
4 0 -rad 0 constraint 1
5 0 0 rad constraint 2 FIXED // to show back hemisphere
6 0 0 -rad constraint 2 FIXED
7 0 rad 0 constraint 2 FIXED
8 -rad 0 0 constraint 2 FIXED
9 0 -rad 0 constraint 2 FIXED
edges:
1 1 2 constraint 1
2 2 3 constraint 1
3 3 4 constraint 1
4 4 1 constraint 1
5 5 9 constraint 2 FIXED // to show back hemisphere
6 9 6 constraint 2 FIXED
7 6 7 constraint 2 FIXED
8 7 5 constraint 2 FIXED
9 5 8 constraint 2 FIXED
10 9 8 constraint 2 FIXED
11 6 8 constraint 2 FIXED
12 7 8 constraint 2 FIXED
faces:
1 1 2 3 4
2 5 10 -9 constraint 2 density 0 FIXED // to show back hemisphere
3 -10 6 11 constraint 2 density 0 FIXED
4 -11 7 12 constraint 2 density 0 FIXED
5 8 9 -12 constraint 2 density 0 FIXED
bodies: // start with sphere half full
1 1 volume 2*pi*rad^3/3 volconst 2*pi*rad^3/3 density RHO
read
// Typical short evolution
gogo := { g 5; r; g 5; r; g 5; r; g 10; conj_grad; g 20; }
// Command to print out coordinates of points along cross-section
// of the surface. This starts at vertex 3 and follows edges that
// point in the positive x direction.
section := {
thisv := 3;
nextv := thisv;
do
{ printf "%9.6f %9.6f %9.6f\n",vertex[thisv].x,vertex[thisv].y,
vertex[thisv].z;
foreach vertex[thisv].edge ee do
{ if ee.x > 10*abs(ee.y) then
{ nextv := ee.vertex[2].id;
break;
}
};
if nextv == thisv then break; // done
thisv := nextv;
} while 1;
}
evolver-2.30c.dfsg/fe/compdump.cmd 0000755 0001753 0001753 00000000605 11410765113 017335 0 ustar hazelsct hazelsct // compdump.cmd
// command for dumping datafile directly to compressed form
//
dumpcmd := sprintf "compress >%s.dmp.Z",datafilename
dodump := { list topinfo;
print "\nvertices\n"; list vertices;
print "\nedges\n"; list edges;
print "\nfaces\n"; list facets;
print "\nbodies\n"; list bodies;
list bottominfo }
compdump := { print dumpcmd; dodump | dumpcmd }
evolver-2.30c.dfsg/fe/bonnet_movie.cmd 0000755 0001753 0001753 00000011424 11410765113 020176 0 ustar hazelsct hazelsct // bonnet_movie.cmd
// Makes in-memory movie of Bonnet rotation of minimal surface,
// one frame per degree for 360 degrees.
// Programmer: Ken Brakke, brakke@susqu.edu, http://www.susqu.edu/brakke
// Usage: Evolve initial minimal surface, remove all level-set constraints
// and boundaries, get nice view in graphics window.
// Run "show_movie" to see screen display of Bonnet rotation.
// Run "postscript_movie" to create sequence of PostScript files.
read "adjoint.cmd"
midvertex := 5 // vertex to keep at origin
frame_delay := 0.03 // seconds between frames
// Store coordinates for complete Bonnet rotation
define vertex attribute bonnet real[360][3]
make_movie := {
local midx,midy,midz;
quiet on;
for ( bangle := 0 ; bangle < 359.5 ; bangle += 1 )
{ adjoint;
midx := vertex[midvertex].x;
midy := vertex[midvertex].y;
midz := vertex[midvertex].z;
foreach vertex vv do
{ vv.bonnet[bangle+1][1] := vv.x-midx;
vv.bonnet[bangle+1][2] := vv.y-midy;
vv.bonnet[bangle+1][3] := vv.z-midz;
};
flip;
};
quiet off;
}
procedure set_bonnet(integer angle)
{
foreach vertex vv do
{ vv.x := vv.bonnet[angle+1][1];
vv.y := vv.bonnet[angle+1][2];
vv.z := vv.bonnet[angle+1][3];
};
recalc;
}
show_movie := {
local next_time;
next_time := clock;
for ( angle := 0; angle < 359.5 ; angle += 1 )
{ while clock < next_time do {};
next_time += frame_delay;
set_bonnet(angle);
}
}
// write postscript file for each frame
postscript_movie := {
full_bounding_box on;
for ( angle := 0; angle < 359.5 ; angle += 1 )
{
set_bonnet(angle);
postscript sprintf"%s.%03d",datafilename,angle;
}
}
// continuous loop
movie := { for (;;) show_movie; }
// Write split-vertex adjoint datafile. To be done after conconj;
// uses enewx values to compute vertices.
define facet attribute split_bonnet real[3][360][3]
write_split_movie := {
printf "// split-vertex discrete adjoint of %s, rotation angle %f.\n",
datafilename,bangle;
printf "\ndefine vertex attribute bonnet real[360][3]\n\n";
printf "\nvertices\n";
foreach facet ff do
{ printf "%d %15.10f %15.10f %15.10f bonnet ",3*ff.id-2,
ff.edge[1].enewx[1]+ff.edge[2].enewx[1]-ff.edge[3].enewx[1],
ff.edge[1].enewx[2]+ff.edge[2].enewx[2]-ff.edge[3].enewx[2],
ff.edge[1].enewx[3]+ff.edge[2].enewx[3]-ff.edge[3].enewx[3];
print ff.split_bonnet[1];
printf "\n";
printf "%d %15.10f %15.10f %15.10f bonnet ",3*ff.id-1,
-ff.edge[1].enewx[1]+ff.edge[2].enewx[1]+ff.edge[3].enewx[1],
-ff.edge[1].enewx[2]+ff.edge[2].enewx[2]+ff.edge[3].enewx[2],
-ff.edge[1].enewx[3]+ff.edge[2].enewx[3]+ff.edge[3].enewx[3];
print ff.split_bonnet[2];
printf "\n";
printf "%d %15.10f %15.10f %15.10f bonnet ",3*ff.id,
ff.edge[1].enewx[1]-ff.edge[2].enewx[1]+ff.edge[3].enewx[1],
ff.edge[1].enewx[2]-ff.edge[2].enewx[2]+ff.edge[3].enewx[2],
ff.edge[1].enewx[3]-ff.edge[2].enewx[3]+ff.edge[3].enewx[3];
print ff.split_bonnet[3];
printf "\n";
};
printf "\nedges\n";
foreach facet ff do
{ printf "%d %d %d\n",3*ff.id-2,3*ff.id-2,3*ff.id-1;
printf "%d %d %d\n",3*ff.id-1,3*ff.id-1,3*ff.id;
printf "%d %d %d\n",3*ff.id,3*ff.id,3*ff.id-2;
};
printf "\nfaces\n";
foreach facet ff do
printf "%d %d %d %d\n",ff.id,3*ff.id-2,3*ff.id-1,3*ff.id;
printf "\nread\n";
printf "read \"bonnet_movie.cmd\"\n";
}
make_split_movie := {
local midx,midy,midz;
quiet on;
for ( bangle := 0 ; bangle < 359.5 ; bangle += 1 )
{ adjoint;
midx := vertex[midvertex].x;
midy := vertex[midvertex].y;
midz := vertex[midvertex].z;
foreach edge ee do
{ ee.enewx[1] -= midx;
ee.enewx[2] -= midy;
ee.enewx[3] -= midz;
};
foreach facet ff do
{
ff.split_bonnet[1][bangle+1][1] :=
ff.edge[1].enewx[1]+ff.edge[2].enewx[1]-ff.edge[3].enewx[1];
ff.split_bonnet[1][bangle+1][2] :=
ff.edge[1].enewx[2]+ff.edge[2].enewx[2]-ff.edge[3].enewx[2];
ff.split_bonnet[1][bangle+1][3] :=
ff.edge[1].enewx[3]+ff.edge[2].enewx[3]-ff.edge[3].enewx[3];
ff.split_bonnet[2][bangle+1][1] :=
-ff.edge[1].enewx[1]+ff.edge[2].enewx[1]+ff.edge[3].enewx[1];
ff.split_bonnet[2][bangle+1][2] :=
-ff.edge[1].enewx[2]+ff.edge[2].enewx[2]+ff.edge[3].enewx[2];
ff.split_bonnet[2][bangle+1][3] :=
-ff.edge[1].enewx[3]+ff.edge[2].enewx[3]+ff.edge[3].enewx[3];
ff.split_bonnet[3][bangle+1][1] :=
ff.edge[1].enewx[1]-ff.edge[2].enewx[1]+ff.edge[3].enewx[1];
ff.split_bonnet[3][bangle+1][2] :=
ff.edge[1].enewx[2]-ff.edge[2].enewx[2]+ff.edge[3].enewx[2];
ff.split_bonnet[3][bangle+1][3] :=
ff.edge[1].enewx[3]-ff.edge[2].enewx[3]+ff.edge[3].enewx[3];
};
flip;
};
quiet off;
}
evolver-2.30c.dfsg/fe/stl.cmd 0000755 0001753 0001753 00000001260 11410765113 016311 0 ustar hazelsct hazelsct // stl.cmd
// Surface Evolver command to produce STL format text file from surface.
// Evolver command line usage:
// read "stl.cmd"
// stl >>> "filename.stl"
// Programmer: Ken Brakke, brakke@susqu.edu, http://www.susqu.edu/brakke
stl := {
local mag,inx;
printf "solid\n";
foreach facet ff do
{ mag := sqrt(ff.x^2+ff.y^2+ff.z^2);
printf "facet normal %f %f %f\n",ff.x/mag,ff.y/mag,ff.z/mag;
printf " outer loop\n";
for ( inx := 1 ; inx <= 3 ; inx += 1 )
printf " vertex %f %f %f\n",ff.vertex[inx].x,ff.vertex[inx].y,
ff.vertex[inx].z;
printf " endloop\n";
printf " endfacet\n";
};
printf "endsolid\n";
}
evolver-2.30c.dfsg/fe/tankex.fe 0000644 0001753 0001753 00000005233 11410765113 016631 0 ustar hazelsct hazelsct // tankex.fe
// Equilibrium shape of liquid in flat-ended cylindrical tank.
// Tank has axis along y-axis and flat bottom in x-z plane. This
// is so gravity acting vertically draws liquid toward wall.
// Straight edges cannot conform exactly to curved walls.
// We need to give them an area so that area cannot shrink by straght edges
// pulling away from the walls. The gaps are also accounted for
// in volume and gravitational energy.
SYMMETRIC_CONTENT // for volume calculations
// Contact angles, initially for 45 degrees.
PARAMETER ENDT = 0.707 /* surface tension of uncovered base */
PARAMETER WALLT = 0.707 /* surface tension of uncovered side wall */
// Gravity components
PARAMETER GY = 0
PARAMETER GZ = -1
SPRING_CONSTANT 1 // for most accurate gap areas for constraint 2
#define TR 1.00 /* tank radius */
#define RHO 1.00 /* fuel density */
constraint 1 // flat base
function: y = 0
energy: // for contact energy line integral
e1: -ENDT*z
e2: 0
e3: 0
#define wstuff (WALLT*TR*y/(x^2 + z^2)) // common wall area term
#define vstuff (TR^2/3*y/(x^2 + z^2)) // common wall volume term
#define gstuff (GY*TR^2*y^2/4/(x^2 + z^2) + GZ*TR^3*y*z/3/(x^2+z^2)**1.5)
// common gap gravity term
constraint 2 CONVEX // cylindrical wall
function: x^2 + z^2 = TR^2
energy: // for contact energy and gravity
e1: -wstuff*z + RHO*GY*y^2*z/4 + RHO*GZ*y*z^2/3 - RHO*gstuff*z
e2: 0
e3: wstuff*x - RHO*GY*y^2*x/4 - RHO*GZ*y*z*x/3 + RHO*gstuff*x
content: // so volumes calculated correctly
c1: vstuff*z - z*y/6 + vstuff*z/2
c2: 0
c3: -vstuff*x + x*y/6 - vstuff*x/2
// named quantity for arbitrary direction gravity on facets
quantity arb_grav energy method facet_vector_integral global
vector_integrand:
q1: 0
q2: -RHO*GY*y^2/2 - RHO*GZ*y*z
q3: 0
// Now the specification of the initial shape
vertices
1 0.5 0.0 0.5 constraint 1
2 0.5 0.0 -0.5 constraint 1
3 -0.5 0.0 -0.5 constraint 1
4 -0.5 0.0 0.5 constraint 1
5 1.0 0.5 0.0 constraint 2
6 0.0 0.5 -1.0 constraint 2
7 -1.0 0.5 0.0 constraint 2
8 0.0 0.5 1.0 constraint 2
edges
1 2 1 constraint 1
2 1 4 constraint 1
3 4 3 constraint 1
4 3 2 constraint 1
5 5 6 constraint 2
6 6 7 constraint 2
7 7 8 constraint 2
8 8 5 constraint 2
9 1 8
10 1 5
11 2 5
12 2 6
13 3 6
14 3 7
15 4 7
16 4 8
faces
1 13 6 -14
2 3 14 -15
3 15 7 -16
4 2 16 -9
5 9 8 -10
6 1 10 -11
7 11 5 -12
8 4 12 -13
bodies
1 1 2 3 4 5 6 7 8 volume 0.6 density 0 /* no default gravity */
evolver-2.30c.dfsg/fe/fourier.cmd 0000755 0001753 0001753 00000003232 11410765113 017163 0 ustar hazelsct hazelsct // fourier.cmd
// Evolver command to print Fourier components for closed curve
// Programmer: Ken Brakke, brakke@susqu.edu, http://www.susqu.edu/brakke
// Usage: f_component(order)
procedure f_component (integer f_order)
// f_order is the order of Fourier components.
{
local e_id,first_e,v_id,newe_id;
x_sin_coeff := 0.0;
y_sin_coeff := 0.0;
z_sin_coeff := 0.0;
x_cos_coeff := 0.0;
y_cos_coeff := 0.0;
z_cos_coeff := 0.0;
ecount := 0;
// get starting edge, since can't assume edge[1] exists
foreach edge do e_id := id;
first_e := e_id;
v_id := edge[e_id].vertex[1].id;
// follow connected edges
do {
local ss,cc,newv_id;
ss := sin(f_order*ecount*2*pi/edge_count)*2/edge_count;
x_sin_coeff := x_sin_coeff + vertex[v_id].x*ss;
y_sin_coeff := y_sin_coeff + vertex[v_id].y*ss;
z_sin_coeff := z_sin_coeff + vertex[v_id].z*ss;
cc := cos(f_order*ecount*2*pi/edge_count)*2/edge_count;
x_cos_coeff := x_cos_coeff + vertex[v_id].x*cc;
y_cos_coeff := y_cos_coeff + vertex[v_id].y*cc;
z_cos_coeff := z_cos_coeff + vertex[v_id].z*cc;
foreach edge[e_id].vertex vv do
{ if ( vv.id != v_id ) then
{ newv_id := vv.id;
foreach vv.edge ee do
if ee.id != e_id then newe_id := ee.id
}
};
e_id := newe_id; v_id := newv_id;
ecount := ecount + 1;
} while ( (e_id != first_e) and (ecount <= edge_count) );
printf "Order %g x y z \n",f_order;
printf "sin: %20.15f %20.15f %20.15f\n",x_sin_coeff,y_sin_coeff,z_sin_coeff;
printf "cos: %20.15f %20.15f %20.15f\n",x_cos_coeff,y_cos_coeff,z_cos_coeff;
}
evolver-2.30c.dfsg/fe/addload_example.fe 0000644 0001753 0001753 00000005735 11410765113 020451 0 ustar hazelsct hazelsct // addload_example.fe
// Demonstration of using the addload command to load multiple
// copies of the same file. Basic surface is that of mound.fe,
// a liquid drop on a plane.
// Each separate mound will have its own contact angle, implemented
// by having a contact angle attribute for each edge.
// The "setup" script below invokes addload multiple times on this same
// datafile, moviing each instance to its appropriate location.
// Note that addload does not execute the "read" section of a datafile,
// so such "setup" scripts are ru only once.
// Programmeer: Ken Brakke, brakke@susqu.edu
define edge attribute angle real // interior angle between plane and surface, degrees
gravity_constant 0 // start with gravity off
#define WALLT (-cos(angle*pi/180)) // virtual tension of facet on plane
constraint 1 /* the table top */
formula: x3 = 0
energy: // for contact angle
e1: -(WALLT*y)
e2: 0
e3: 0
vertices
1 0.0 0.0 0.0 constraint 1 /* 4 vertices on plane */
2 1.0 0.0 0.0 constraint 1
3 1.0 1.0 0.0 constraint 1
4 0.0 1.0 0.0 constraint 1
5 0.0 0.0 1.0
6 1.0 0.0 1.0
7 1.0 1.0 1.0
8 0.0 1.0 1.0
9 2.0 2.0 0.0 fixed /* for table top */
10 2.0 -1.0 0.0 fixed
11 -1.0 -1.0 0.0 fixed
12 -1.0 2.0 0.0 fixed
edges /* given by endpoints and attribute */
1 1 2 constraint 1 /* 4 edges on plane */
2 2 3 constraint 1
3 3 4 constraint 1
4 4 1 constraint 1
5 5 6
6 6 7
7 7 8
8 8 5
9 1 5
10 2 6
11 3 7
12 4 8
13 9 10 no_refine fixed /* for table top */
14 10 11 no_refine fixed
15 11 12 no_refine fixed
16 12 9 no_refine fixed
faces /* given by oriented edge loop */
1 1 10 -5 -9
2 2 11 -6 -10
3 3 12 -7 -11
4 4 9 -8 -12
5 5 6 7 8
7 13 14 15 16 no_refine density 0 fixed /* table top for display */
bodies /* one body, defined by its oriented faces */
1 1 2 3 4 5 volume 1 density 1
read
setup := {
// Read in 3 x 3 arrangement of drops. The first has already been
// read in, so we need to read in 8 more copies of this datafile.
// We use a vertex attribute to distinguish between old and new
// elements; for more elaborate massaging of new input you could
// use more attributes on more types of elements.
define vertex attribute load_marker integer;
for ( row := 0 ; row < 3 ; row += 1 )
for ( col := 0 ; col < 3 ; col += 1 )
{ if ( row > 0 or col > 0 ) then addload datafilename;
// Move and mark vertices
foreach vertex vv where load_marker == 0 do
{ vv.x += 2*row;
vv.y += 2*col;
vv.load_marker := 3*row+col+1; // different loads get different marks
};
};
// Now assign contact angles to contact line edges
foreach edge ee where on_constraint 1 do
ee.angle := 90 + (ee.vertex[1].load_marker - 5)*10;
} // end setup
setup
// From here on, we have the usual evolution commands
re := {refine edges where on_constraint 1 }
// Typical evolution
gogo := { re; g 5; r; g 5; r; g 5; hessian; hessian; }
evolver-2.30c.dfsg/fe/catbody.fe 0000644 0001753 0001753 00000005011 11410765113 016756 0 ustar hazelsct hazelsct // catbody.fe
// Evolver data for catenoid with fixed inner volume between plane ends.
PARAMETER RMAX = 1.0
PARAMETER ZMAX = 0.55
boundary 1 parameters 1 // upper ring
x1: RMAX * cos(p1)
x2: RMAX * sin(p1)
x3: ZMAX
boundary 2 parameters 1 // lower ring
x1: RMAX * cos(p1)
x2: RMAX * sin(p1)
x3: -ZMAX
vertices // given in terms of boundary parameter
1 0.00 boundary 1 fixed
2 pi/3 boundary 1 fixed
3 2*pi/3 boundary 1 fixed
4 pi boundary 1 fixed
5 4*pi/3 boundary 1 fixed
6 5*pi/3 boundary 1 fixed
7 0.00 boundary 2 fixed
8 pi/3 boundary 2 fixed
9 2*pi/3 boundary 2 fixed
10 pi boundary 2 fixed
11 4*pi/3 boundary 2 fixed
12 5*pi/3 boundary 2 fixed
edges
1 1 2 boundary 1 fixed
2 2 3 boundary 1 fixed
3 3 4 boundary 1 fixed
4 4 5 boundary 1 fixed
5 5 6 boundary 1 fixed
6 6 1 boundary 1 fixed
7 7 8 boundary 2 fixed
8 8 9 boundary 2 fixed
9 9 10 boundary 2 fixed
10 10 11 boundary 2 fixed
11 11 12 boundary 2 fixed
12 12 7 boundary 2 fixed
13 1 7
14 2 8
15 3 9
16 4 10
17 5 11
18 6 12
faces
1 13 7 -14 -1
2 14 8 -15 -2
3 15 9 -16 -3
4 16 10 -17 -4
5 17 11 -18 -5
6 18 12 -13 -6
bodies
1 1 2 3 4 5 6 volconst 2*pi*rmax^2*zmax volume 1.1
read
// Typical evolution
gogo := { u; r; g 5; r; g 5; r; g 5; hessian; hessian }
// Adjusting volume to find zero pressure, i.e. the unstable
// equilibrium catenoid. Run after refining to taste.
// Note that no 'g' steps are used in iteration after changing
// the volume. This is because the triangulation is not optimal,
// and 'g' lets the vertices slither sideways, but 'hessian'
// moves vertices only perpendicular to the surface (in the default
// hessian_normal mode). The magnitude of volume changes is limited
// since experimentation showed that too large moves can cause
// blowups.
adjust := {
oldpressure := body[1].pressure;
oldtarget := body[1].target;
dvol := .01; // starting step size
body[1].target += dvol;
hessian; hessian; hessian;
slope := (body[1].pressure - oldpressure)/dvol;
for ( inx := 1 ; inx <= 20; inx += 1 )
{ dvol := -body[1].pressure/slope;
if abs(dvol) > .01 then dvol := (dvol < 0) ? -.01 : .01;
oldpressure := body[1].pressure;
body[1].target += dvol;
hessian; hessian; hessian;
printf "Pressure %g dvol %g slope %f\n",body[1].pressure,dvol,slope;
if abs(dvol) > .001 then
slope := (body[1].pressure - oldpressure)/dvol;
};
}
evolver-2.30c.dfsg/fe/saveview.cmd 0000755 0001753 0001753 00000002436 11410765113 017346 0 ustar hazelsct hazelsct // saveview.cmd
// Evolver command for saving current view matrix in proper form
// for reading in.
// Typical usage: saveview >>> "viewfile.cmd"
// Then to restore view: read "viewfile.cmd"
// Programmer: Ken Brakke, brakke@susqu.edu, http://www.susqu.edu/brakke
saveview := {
printf "oldautodisplay := (autodisplay);\n";
printf "autodisplay off\n";
printf "view_matrix[1][1] := %f\n",view_matrix[1][1];
printf "view_matrix[1][2] := %f\n",view_matrix[1][2];
printf "view_matrix[1][3] := %f\n",view_matrix[1][3];
printf "view_matrix[1][4] := %f\n",view_matrix[1][4];
printf "view_matrix[2][1] := %f\n",view_matrix[2][1];
printf "view_matrix[2][2] := %f\n",view_matrix[2][2];
printf "view_matrix[2][3] := %f\n",view_matrix[2][3];
printf "view_matrix[2][4] := %f\n",view_matrix[2][4];
printf "view_matrix[3][1] := %f\n",view_matrix[3][1];
printf "view_matrix[3][2] := %f\n",view_matrix[3][2];
printf "view_matrix[3][3] := %f\n",view_matrix[3][3];
printf "view_matrix[3][4] := %f\n",view_matrix[3][4];
printf "view_matrix[4][1] := %f\n",view_matrix[4][1];
printf "view_matrix[4][2] := %f\n",view_matrix[4][2];
printf "view_matrix[4][3] := %f\n",view_matrix[4][3];
printf "view_matrix[4][4] := %f\n",view_matrix[4][4];
printf "if oldautodisplay then autodisplay on\n";
}
evolver-2.30c.dfsg/fe/band.cmd 0000755 0001753 0001753 00000012145 11410765113 016417 0 ustar hazelsct hazelsct // band.cmd
// Surface Evolver command to create triangulated band bordering
// deisgnated edges and vertices. Purpose is to make extremely
// accurate PostScript files without notching on thick edges.
// Programmer: Ken Brakke, brakke@susqu.edu, http://www.susqu.edu/brakke
// WARNING: This command modifies the surface by creating a lot of
// tiny facets. You should use only on a disposable copy of your surface.
// Usage: set bandcolor and bandwidth to desired values; bandwidth is
// the width of the band in surface coordinates on one
// side of an edge.
// set the edge attribute inband to nonzero for those edges
// to have band drawn along them.
// run makeband
// When creating PostScript file, use the NN response to P 3 "Show grid lines?"
// IMPORTANT NOTE: The algorithm has trouble where inband edges meet
// at an angle, since each vertex has a single band distance attribute
// and the vertex may be a neighbor to two different bands. This results
// in ragged bands near corners. A cure is to do banding in stages,
// doing one "original" edge at a time.
// Not wise to run more than once along a given edge. Numerical
// variations due to new vertices lead to a lot more unnecessary
// refinements.
define edge attribute inband integer // 1 if band center, 0 if not
define vertex attribute banddist real // distance from band center.
define facet attribute bandused integer // so use each facet at most once
bandcolor := black // Set this to desired color before makeband.
bandwidth := 0.010 // Set this to desired half-width before makeband.
makeband := {
local maxbanddist,changed,eps;
maxbanddist := 100000*bandwidth;
set vertex banddist maxbanddist;
foreach edge ee where inband do set ee.vertex banddist 0;
foreach edge ee where (ee.inband==0) and (ee.vertex[1].banddist==0)
and (ee.vertex[2].banddist==0)
do { refine ee; ee.vertex[2].banddist := maxbanddist; } ;
set facet bandused 0;
// Calculate vertex distances from band center
do
{ changed := 0;
foreach facet ff do
{ local s1,s2,s3,d1,d2,d3;
local newd1,newd2,newd3;
if ff.bandused then continue;
s1 := ff.edge[1].length;
s2 := ff.edge[2].length;
s3 := ff.edge[3].length;
d1 := ff.vertex[1].banddist;
d2 := ff.vertex[2].banddist;
d3 := ff.vertex[3].banddist;
if ( (d2 < d1 or d3 < d1) and
( ( (d2 < bandwidth) && (d3 < maxbanddist) )
or ( (d2 < maxbanddist) && (d3 < bandwidth) ) ) ) then
{ newd1 := d3 + s3*sin(asin((d2-d3)/s2)+acos((-s1^2+s2^2+s3^2)/2/s2/s3));
if ( newd1 > 0 and newd1 < d1 ) then
{ ff.vertex[1].banddist := newd1; changed += 1;
ff.bandused := 1; continue;
};
};
if ( (d1 < d2 or d3 < d2 ) and
( ( (d1 < bandwidth) && (d3 < maxbanddist) )
or ( (d1 < maxbanddist) && (d3 < bandwidth) ) ) ) then
{ newd2 := d1 + s1*sin(asin((d3-d1)/s3)+acos((-s2^2+s3^2+s1^2)/2/s3/s1));
if ( newd2 > 0 and newd2 < d2 ) then
{ ff.vertex[2].banddist := newd2; changed += 1;
ff.bandused := 1; continue;
};
};
if ( (d1 < d3 or d2 < d3 ) and
( ( (d1 < bandwidth) && (d2 < maxbanddist) )
or ( (d1 < maxbanddist) && (d2 < bandwidth) ) ) ) then
{ newd3 := d2 + s2*sin(asin((d1-d2)/s1)+acos((-s3^2+s1^2+s2^2)/2/s1/s2));
if ( newd3 > 0 and newd3 < d3 ) then
{ ff.vertex[3].banddist := newd3; changed += 1;
ff.bandused := 1; continue;
};
};
};
} while ( changed > 0 );
printf "\n";
// Subdivide edges spanning band boundary
eps := 1e-4*bandwidth; // numerical margin for error
foreach edge ee do
{ local d1,d2;
local new_x,new_y,new_z;
local lambda;
d1 := ee.vertex[1].banddist;
d2 := ee.vertex[2].banddist;
if ( ((d1<=bandwidth+eps)&&(d2<=bandwidth+eps)) ||
((d1>=bandwidth-eps)&&(d2>=bandwidth-eps)))
then continue;
lambda := (bandwidth - d2)/(d1 - d2);
if ( lambda < .00001 or lambda > .99999 ) then continue;
new_x := lambda*ee.vertex[1].x + (1-lambda)*ee.vertex[2].x;
new_y := lambda*ee.vertex[1].y + (1-lambda)*ee.vertex[2].y;
new_z := lambda*ee.vertex[1].z + (1-lambda)*ee.vertex[2].z;
refine ee;
ee.vertex[2].x := new_x;
ee.vertex[2].y := new_y;
ee.vertex[2].z := new_z;
ee.vertex[2].banddist := bandwidth;
};
// Color band triangles
foreach facet ff do
{ if avg(ff.vertex,banddist) < bandwidth then set ff color bandcolor; };
}
// to do edges on different constraints one constraint at a time.
cband := {
local connum;
for ( connum := 1 ; connum <= high_constraint ; connum += 1 )
{ if valid_constraint(connum) then
{ set edge inband on_constraint connum;
makeband;
}
};
}
// makeband usage:
// set bandwidth to desired half-width (in surface coordinates)
// set edge inband to 1 along band center, 0 elsewhere
// set bandcolor to desired color
// run makeband
// In making postscript, answer N to gridlines, and y to colors.
evolver-2.30c.dfsg/fe/strdup.cmd 0000755 0001753 0001753 00000002657 11410765113 017043 0 ustar hazelsct hazelsct // strdup.cmd
// Evolver command to write a datafile that is an n-fold
// covering of a string. Meant to generate multiple coverings
// of elastic figure 8's.
// Usage: set dupnum to desired multiple and run "strdup".
// Programmer: Ken Brakke, brakke@susqu.edu, http://www.susqu.edu/brakke
dupnum := 2 // covering order
strdup := {
local sheet,vbase,connectflag,swapedge,ebase;
list topinfo;
printf "\nvertices\n";
sheet := 0;
while ( sheet < dupnum ) do
{ vbase := sheet*vertex_count;
foreach vertex do
printf "%g %g %g\n",id+vbase,x,y;
sheet := sheet + 1;
};
printf "\nedges\n";
connectflag := 0;
sheet := 0;
swapedge := -1;
while ( sheet < dupnum ) do
{ ebase := sheet*edge_count;
vbase := sheet*vertex_count;
foreach edge ee do
{ if connectflag and (swapedge != ee.id) then
printf "%g %g %g\n",
ee.id+ebase,ee.vertex[1].id+vbase,ee.vertex[2].id+vbase
else
{ printf "%g %g %g\n",
ee.id+ebase,ee.vertex[1].id+vbase,
ee.vertex[2].id+((sheet+1)imod dupnum)*vertex_count;
connectflag := 1;
swapedge := ee.id;
}
};
sheet := sheet + 1;
};
printf "\nread\n";
list procedures;
} // end strdup
evolver-2.30c.dfsg/fe/README-cmd.txt 0000644 0001753 0001753 00000006254 11410765113 017266 0 ustar hazelsct hazelsct A selection of Evolver commands for your edification. Consult remarks at
the top of each file for further information and instructions on use.
Use with caution; no attempt has been made to bulletproof these.
Note: These scripts do not necessarily take advantage of all the latest
Evolver features, and if I were writing them from scratch now they might
turn out quite different.
adjoint.cmd
ansurf.cmd Produces input file for ANSYS.
band.cmd Make extremely accurate thick borders for graphics.
bonnet_movie.cmd Show Bonnet rotation of minimal surface.
cmccousin.cmd Create constant mean curvature "cousin" surface.
dirichlet_to_disk.cmd Makes conformal map to disk by minimizing Dirichlet energy.
dxf.cmd Produce AutoCad DXF file.
equi.cmd To color edges subject to equiangulation.
equi2.cmd To color edges subject to equiangulation.
fourier.cmd Calculate Fourier components for closed curve
gaussequi.cmd Equiangulation using Gauss map for swap criterion.
gaussmap.cmd Converts each vertex coordinate to unit normal.
gaussref.cmd Refining using Gauss map as criterion.
iges.cmd Create file in IGES text format.
iges128.cmd Create IGES file using B-spline entity (type 128).
iges136.cmd Create IGES file using finite element entity (type 136).
intersec.cmd Detect intersection of linear edges and facets.
jvx.cmd Creates JVX format file for JavaView.
multiplicate.cmd Create datafile with multiple copies of surface.
neville.cmd Neville's algorithm for interpolating b-splines in 1D and 2D.
off.cmd Prints OFF format file.
order.cmd Numbers string vertices consecutively.
orderdmp.cmd Number string vertices consecutively and create an ordered dump file.
orderlis.cmd Number string vertices consecutively and list them
polyfilm.cmd Produce Polycut format file
povray.cmd Produces POV-Ray input file.
povrays.cmd POV-Ray file with smooth shading.
quadbbox.cmd Finds bounding boxes for quadratic facets in 3D
quadint2.cmd For detecting intersection of quadratic facets in 3D
quadmeet.cmd For detecting intersection of quadratic facets in 3D
reorder.cmd Example of using "reorder_storage" command.
rewrap.cmd Adjusting wraps of edges in 3D torus model.
rewrap2.cmd Adjusting wraps of edges in 2D torus model.
rib.cmd Creates Renderman RIB file.
rotate.cmd Rotate unfixed vertices by angle about z axis.
saveview.cmd Saves view matrix in easily reloadable form.
slice.cmd Calculate length of intersection of plane with surface.
slice2.cmd Calculates length of intersection of plane with one body.
slicer.cmd Create physical intersection of surface and plane.
stl.cmd Creates file in STL stereolithography format.
strdup.cmd Writes a datafile that is an n-fold covering of a string.
tuber.cmd Creates tubes around certain edges.
unshear.cmd Morphs 2D torus fundamental region to rectangle.
vrml.cmd Makes VRML file for surface.
wavefront.cmd Creates Wavefront format file.
wetfoam2.cmd Creates Plateau borders on a dry foam.
x3d.cmd Creates X3D format file.
xray.cmd Creates PostScript file with x-ray image.
zebra.cmd Colors string edges alternately black and white
evolver-2.30c.dfsg/fe/iges.cmd 0000755 0001753 0001753 00000017536 11410765113 016453 0 ustar hazelsct hazelsct // iges.cmd
// Surface Evolver script to write IGES file for surface, using IGES
// finite element entity (type 136), which handles linear, quadratic,
// and cubic triangles (among many other types not of interest).
// Finite element type not official "geometry"???? Rhino says can't
// find any independent geometry, and http://www.iges5x.org/taxonomy/ has
// FEM types included under "non-geometry taxonomy'.
// Also not listed in Table 3 on p. 38 of IGES-6 documentation.
// So we try using parametric patches, type 114.
// Programmer: Ken Brakke, brakke@susqu.edu, http://www.susqu.edu/brakke
// usage: iges >>> "filename.igs"
// Set up color translation array
define iges_colors integer [16];
//iges_colors[black] := 1
iges_colors[red] := 2
iges_colors[green] := 3
iges_colors[blue] := 4
iges_colors[yellow] := 5
iges_colors[magenta] := 6
iges_colors[cyan] := 7
iges_colors[white] := 8
iges_colors[brown] := 2 // red
iges_colors[lightgray] := 8 // white
iges_colors[darkgray] := 1 // black
iges_colors[lightblue] := 4 // blue
iges_colors[lightcyan] := 7 // cyan
iges_colors[lightred] := 2 // red
iges_colors[lightmagenta] := 7
iges := {
local start_counter,global_counter,message,xmax,ymax,zmax;
local maxsize,entype,paramdata,structure,linefont,level,view;
local transmat,label,status,directory_counter,lineweight;
local colornum,paramcount,form,reserved,entlabel,entsubscr;
local parameter_counter,ctype,ptype,mvalue,nvalue,minu,maxu;
local minv,maxv,co00,co10,co01,co11,line,subcount;
// Flag section
// Don't need this since not doing binary or compressed format.
// Start section
start_counter := 0;
start_counter += 1;
printf "%-72sS%07d\n","IGES version of Surface Evolver surface",start_counter;
start_counter += 1;
printf " %-69sS%07d\n",datafilename,start_counter;
start_counter += 1;
printf "%-72sS%07d\n","Created using iges.cmd Evolver script.",
start_counter;
// Global section
global_counter := 0;
global_counter += 1;
printf "%-72sG%07d\n","1H,,1H;,",global_counter;
global_counter += 1;
printf "%02dH%-69sG%07d\n",sizeof("Surface Evolver"),"Surface Evolver,",
global_counter;
global_counter += 1;
message := sprintf "%s,",datafilename;
printf "%02dH%-69sG%07d\n",sizeof(datafilename),message,global_counter;
global_counter += 1;
printf "%02dH%-69sG%07d\n",sizeof("Surface Evolver"),"Surface Evolver,",
global_counter;
global_counter += 1;
printf "%02dH%-69sG%07d\n",sizeof("Surface Evolver"),"Surface Evolver,",
global_counter;
global_counter += 1;
printf "%-72sG%07d\n","32,75,6,75,15,,1.0,1,2HIN,32768,0.0394,",
global_counter;
global_counter += 1;
printf "%-72sG%07d\n","15H00000000.000000,", global_counter; // date
xmax := max(vertex,abs(x));
ymax := max(vertex,abs(y));
zmax := max(vertex,abs(z));
maxsize := (xmax > ymax) ? xmax : ymax;
maxsize := (zmax > maxsize) ? zmax : maxsize;
message := sprintf "%g,%g,",maxsize/10000000,maxsize;
global_counter += 1;
printf "%-72sG%07d\n",message, global_counter;
global_counter += 1;
printf "%02dH%-69sG%07d\n",sizeof("Name of author"),"Name of author,",
global_counter;
global_counter += 1;
printf "%02dH%-69sG%07d\n",sizeof("Author's organization"),
"Author's organization,", global_counter;
global_counter += 1;
printf "%-72sG%07d\n","15H00000000.000000;", global_counter; // date
// Directory entry section. Each entry 20 8-char fields on two lines.
// Fields with default values
entype := 0; // 1 and 11
paramdata := 1; // 2
structure := 0; // 3
linefont := 0; // 4
level := 0; // 5
view := 0; // 6
transmat := 0; // 7
label := 0; // 8
status := "00000000"; // 9; actually 4 two-digit numbers
directory_counter := 0; // 10 and 20
lineweight := 0; // 12
colornum := 0; // 13
paramcount := 0; // 14
form := 0; // 15
reserved := " "; // 16 and 17
entlabel := "entity"; // 18
entsubscr := 0; // 19
// Facets as "parametric surface" types
entype := 114;
status := "00010001";
paramcount := 1;
entlabel := " FACET";
define facet attribute fpdata integer;
define facet attribute fdir integer;
foreach facet ff do
{ ff.fpdata := paramdata;
entsubscr := ff.id;
directory_counter += 1; ff.fdir := directory_counter;
printf "%8d%8d%8d%8d%8d%8d%8d%8d%8sD%7d\n",entype,paramdata,structure,
linefont,level,view,transmat,label,status,directory_counter;
directory_counter += 1;
printf "%8d%8d%8d%8d%8d%8s%8s%8s%8dD%7d\n",entype,lineweight,
iges_colors[ff.color],
paramcount,form,reserved,reserved,entlabel,entsubscr,directory_counter;
paramdata += 7;
};
// Geometry element
entype := 402;
status := "00000301";
paramcount := ceil(facet_count/10);
form := 7;
entlabel := " SURFACE";
entsubscr := 1;
directory_counter += 1;
printf "%8d%8d%8d%8d%8d%8d%8d%8d%8sD%7d\n",entype,paramdata,structure,
linefont,level,view,transmat,label,status,directory_counter;
directory_counter += 1;
printf "%8d%8d%8d%8d%8d%8s%8s%8s%8dD%7d\n",entype,lineweight,colornum,
paramcount,form,reserved,reserved,entlabel,entsubscr,directory_counter;
// Parameter data section
parameter_counter := 0;
// Facets
entype := 114;
ctype := 1; // linear
ptype := 0; // unspecified
mvalue := 1; // number of u segments
nvalue := 1; // number of v segments
minu := 0;
maxu := 1;
minv := 0;
maxv := 1;
foreach facet ff do
{ parameter_counter += 1;
if ff.fpdata != parameter_counter then
errprintf
"ERROR: bad facet parameter line number, facet %d. Is %d, should be %d.\n",
ff.id,parameter_counter,ff.fpdata;
message := sprintf "%d,%d,%d,%d,%d,%g,%g,%g,%g,",entype,ctype,ptype,
mvalue,nvalue,minu,maxu,minv,maxv;
printf "%-64s%8dP%7d\n",message,ff.fdir,parameter_counter;
co00 := ff.vertex[1].x;
co10 := ff.vertex[2].x-ff.vertex[1].x;
co01 := ff.vertex[3].x-ff.vertex[1].x;
co11 := ff.vertex[1].x-ff.vertex[2].x;
message := sprintf "%10.7f,%10.7f,0,0,%10.7f,%10.7f,0,0,",
co00,co10,co01,co11;
parameter_counter += 1;
printf "%-64s%8dP%7d\n",message,ff.fdir,parameter_counter;
message := "0,0,0,0,0,0,0,0,";
parameter_counter += 1;
printf "%-64s%8dP%7d\n",message,ff.fdir,parameter_counter;
co00 := ff.vertex[1].y;
co10 := ff.vertex[2].y-ff.vertex[1].y;
co01 := ff.vertex[3].y-ff.vertex[1].y;
co11 := ff.vertex[1].y-ff.vertex[2].y;
message := sprintf "%10.7f,%10.7f,0,0,%10.7f,%10.7f,0,0,",
co00,co10,co01,co11;
parameter_counter += 1;
printf "%-64s%8dP%7d\n",message,ff.fdir,parameter_counter;
message := "0,0,0,0,0,0,0,0,";
parameter_counter += 1;
printf "%-64s%8dP%7d\n",message,ff.fdir,parameter_counter;
co00 := ff.vertex[1].z;
co10 := ff.vertex[2].z-ff.vertex[1].z;
co01 := ff.vertex[3].z-ff.vertex[1].z;
co11 := ff.vertex[1].z-ff.vertex[2].z;
message := sprintf "%10.7f,%10.7f,0,0,%10.7f,%10.7f,0,0,",
co00,co10,co01,co11;
parameter_counter += 1;
printf "%-64s%8dP%7d\n",message,ff.fdir,parameter_counter;
message := "0,0,0,0,0,0,0,0,";
parameter_counter += 1;
printf "%-64s%8dP%7d\n",message,ff.fdir,parameter_counter;
};
// Geometry element
line := sprintf "402,%d,",facet_count;
subcount := 0;
foreach facet ff do
{ if subcount == 10 then
{
parameter_counter += 1;
printf "%-64s%8dP%7d\n",line,directory_counter-1,parameter_counter;
line := "" ;
subcount := 0;
};
line := sprintf"%s%d,",line,ff.fdir;
subcount += 1;
};
line := sprintf "%s0,0;",line; // sample files ended with 2 extra 0's
parameter_counter += 1;
printf "%-64s%8dP%7d\n",line,directory_counter-1,parameter_counter;
// Terminate section
printf "S%07dG%07dD%07dP%07d%40sT0000001\n",start_counter,global_counter,
directory_counter,parameter_counter," ";
}
evolver-2.30c.dfsg/fe/rewrap2.cmd 0000755 0001753 0001753 00000002400 11410765113 017066 0 ustar hazelsct hazelsct // rewrap2.cmd
// Commands to rewrap torus vertices and edges to get them nicely
// within unit cell. 2D version. For 3D version, see rewrap.cmd.
// Moves vertices at most one period at a time, so you may have to
// repeat if things are very bad to start with.
// Uses torus wrap representation and wrap_vertex builtin command.
// Usage: rewrap2
rewrap2 := {
if space_dimension != 2 then
{ errprintf"rewrap2 is for space dimension 2; for 3D use rewrap3.cmd.\n";
return;
};
define body attribute old_volume real; // so can adjust volconst
set body old_volume volume;
foreach vertex vv where vv.x*inverse_periods[1][1]+vv.y*inverse_periods[1][2]
< 0 do wrap_vertex(vv.id,1);
foreach vertex vv where vv.x*inverse_periods[1][1]+vv.y*inverse_periods[1][2]
>= 1 do wrap_vertex(vv.id,31);
foreach vertex vv where vv.x*inverse_periods[2][1]+vv.y*inverse_periods[2][2]
< 0 do wrap_vertex(vv.id,64);
foreach vertex vv where vv.x*inverse_periods[2][1]+vv.y*inverse_periods[2][2]
>= 1 do wrap_vertex(vv.id,1984);
recalc;
local torvol;
torvol := abs(torus_periods[1][1]*torus_periods[2][2]
- torus_periods[1][2]*torus_periods[2][1]);
set body volconst floor((old_volume - volume - volconst)/torvol+.5)*torvol;
}
evolver-2.30c.dfsg/fe/orderlis.cmd 0000755 0001753 0001753 00000002022 11410765113 017327 0 ustar hazelsct hazelsct // orderlist.cmd
// Evolver command to number string vertices consecutively
// by means of extra attribute 'number'.
// And list them to stdout. Can be redirected to file.
// Programmer: Ken Brakke, brakke@susqu.edu, http://www.susqu.edu/brakke
// Usage: orderlist
define vertex attribute number integer
orderlist := {
local ecount,e_id,first_e,v_id,newv_id,newe_id;
ecount := 0; // for safety
// get starting edge, since can't assume edge[1] exists
foreach edge do { e_id := id; break; };
first_e := e_id;
v_id := edge[e_id].vertex[1].id;
// follow connected edges
do
{ set vertex[v_id] number ecount+1;
printf "%g %g %g\n",vertex[v_id].x,vertex[v_id].y,vertex[v_id].z;
foreach edge[e_id].vertex vv do
{ if ( vv.id != v_id ) then
{ newv_id := vv.id;
foreach vv.edge ee do
if ee.id != e_id then newe_id := ee.id
}
};
e_id := newe_id; v_id := newv_id;
ecount := ecount + 1;
} while ( (e_id != first_e) and (ecount <= edge_count) )
}
evolver-2.30c.dfsg/fe/neville.cmd 0000755 0001753 0001753 00000014052 11410765113 017150 0 ustar hazelsct hazelsct // neville.cmd
// Neville's algorithm for computing Bspline values
// Programmer: Ken Brakke, brakke@susqu.edu, http://www.susqu.edu/brakke
// Contents:
// neville1 - interpolation and derivatives in one dimension
// neville2 - interpolation and derivatives in two dimensions.
// Neville algorithm for interpolating along one dimension.
// Usage of neville1:
// neville1_data should be set up by caller, redimensioning if necessary
// Indexed by point number along curve and data dimension.
define neville1_data real[0][0]; // not modified by neville1
// Returned from neville1. Index is data dimension.
define neville1_value real[0]; // interpolated values
define neville1_deriv real[0]; // interpolated deriv wrt u
procedure neville1 (
real neville1_order, // order of interpolation polynomial
real neville1_dim, // range dimension
real neville1_u // interpolation spot, between 0 and 1
)
{
local neville1_array; local neville1_darray;
define neville1_array real[neville1_order+1][neville1_dim];
define neville1_darray real[neville1_order+1][neville1_dim];
define neville1_value real[neville1_dim]; // interpolated values
define neville1_deriv real[neville1_dim]; // interpolated deriv wrt u
local inx;local dinx;
inx := 1;
while ( inx <= neville1_order+1 ) do
{
dinx := 1;
while ( dinx <= neville1_dim ) do
{ neville1_array[inx][dinx] := neville1_data[inx][dinx];
neville1_darray[inx][dinx] := 0;
dinx += 1;
};
inx += 1;
};
// scale npoint to integer based value
local nnpoint;
nnpoint := neville1_u*neville1_order;
local linx;
linx := 1;
while ( linx <= neville1_order ) do
{ inx := 1;
while ( inx + linx <= neville1_order + 1 ) do
{ dinx := 1;
while ( dinx <= neville1_dim ) do
{ // do derivatives first, since dependent on current value
neville1_darray[inx][dinx] :=
((inx-1+linx - nnpoint)*neville1_darray[inx][dinx]
+ (nnpoint - (inx-1))*neville1_darray[inx+1][dinx])/linx +
(-neville1_array[inx][dinx] + neville1_array[inx+1][dinx])/linx;
neville1_array[inx][dinx] :=
((inx-1+linx - nnpoint)*neville1_array[inx][dinx]
+ (nnpoint - (inx-1))*neville1_array[inx+1][dinx])/linx;
dinx += 1;
};
inx += 1;
};
linx += 1;
};
dinx := 1;
while ( dinx <= neville1_dim ) do
{ neville1_value[dinx] := neville1_array[1][dinx];
neville1_deriv[dinx] := neville1_darray[1][dinx]*neville1_order;
dinx += 1;
};
}
// Neville algorithm for interpolating in 2D
// Usage of neville2:
// Initialize neville2_data, neville2_u arrays.
// Call neville2.
// Input data, indexed by (i,j) node coordinate and data dimension.
define neville2_data real[0][0][0];
define neville2_u real[2]; // incoming; should sum to at most 1
neville2_u[1] := 1/3;
neville2_u[2] := 1/3;
// Return values, indexed by data dimension.
define neville2_value real[0] // return values of position
define neville2_deriv real[0][2] // return values of partials
procedure neville2 (
real neville2_order, // of polynomial
real neville2_dim // dimension of values
)
{
local neville2_array; local neville2_darray; local unpoint;
define neville2_array
real[neville2_order+1][neville2_order+1][neville2_dim];
define neville2_darray
real[neville2_order+1][neville2_order+1][neville2_dim][2];
define uupoint real[2]; // scaled target coordinates
define neville2_value real[neville2_dim]; // return values of position
define neville2_deriv real[neville2_dim][2]; // return values of partials
// initialize data; kludge due to fact that indexing on vertices
// only does the three corners.
local inx; local jnx; local dinx;
inx := 1;
while ( inx <= neville2_order+1 ) do
{ jnx := 1;
while ( inx + jnx <= neville2_order+2 ) do
{ dinx := 1;
while ( dinx <= neville2_dim ) do
{ neville2_array[inx][jnx][dinx] := neville2_data[inx][jnx][dinx];
neville2_darray[inx][jnx][dinx][1] := 0;
neville2_darray[inx][jnx][dinx][2] := 0;
dinx += 1;
};
jnx += 1;
};
inx += 1;
};
// scale npoint to integer based value
uupoint[1] := neville2_u[1]*neville2_order;
uupoint[2] := neville2_u[2]*neville2_order;
local linx;
linx := 1;
while ( linx <= neville2_order ) do
{ inx := 1;
while ( inx + linx <= neville2_order + 1 ) do
{ jnx := 1;
while ( inx + jnx + linx <= neville2_order + 2 ) do
{ dinx := 1;
while ( dinx <= neville2_dim ) do
{ // do derivatives first, since dependent on current value
neville2_darray[inx][jnx][dinx][1] :=
((inx+jnx-2+linx-uupoint[1]-uupoint[2])
*neville2_darray[inx][jnx][dinx][1]
+ (uupoint[1]-(inx-1))*neville2_darray[inx+1][jnx][dinx][1]
+ (uupoint[2]-(jnx-1))*neville2_darray[inx][jnx+1][dinx][1])/linx
+ (-neville2_array[inx][jnx][dinx]
+ neville2_array[inx+1][jnx][dinx] )/linx;
neville2_darray[inx][jnx][dinx][2] :=
((inx+jnx-2+linx-uupoint[1]-uupoint[2])
*neville2_darray[inx][jnx][dinx][2]
+ (uupoint[1]-(inx-1))*neville2_darray[inx+1][jnx][dinx][2]
+ (uupoint[2]-(jnx-1))*neville2_darray[inx][jnx+1][dinx][2])/linx
+ (-neville2_array[inx][jnx][dinx]
+ neville2_array[inx][jnx+1][dinx] )/linx;
neville2_array[inx][jnx][dinx] :=
((inx+jnx-2+linx-uupoint[1]-uupoint[2])*neville2_array[inx][jnx][dinx]
+ (uupoint[1] - (inx-1))*neville2_array[inx+1][jnx][dinx]
+ (uupoint[2] - (jnx-1))*neville2_array[inx][jnx+1][dinx])/linx;
dinx += 1;
};
jnx += 1;
};
inx += 1;
};
linx += 1;
};
dinx := 1;
while ( dinx <= neville2_dim ) do
{ neville2_value[dinx] := neville2_array[1][1][dinx];
neville2_deriv[dinx][1] := neville2_darray[1][1][dinx][1]*neville2_order;
neville2_deriv[dinx][2] := neville2_darray[1][1][dinx][2]*neville2_order;
dinx += 1;
};
}
evolver-2.30c.dfsg/fe/slicer.cmd 0000755 0001753 0001753 00000015666 11410765113 017007 0 ustar hazelsct hazelsct // slicer.cmd --- create intersection of surface with plane
// plane eq: a*x + b*y + c*z = d
// Programmer: Ken Brakke, brakke@susqu.edu, http://www.susqu.edu/brakke
// Commands included:
// drawslice - make new edges across facets along plane.
// slicer - make slice and dissolve all facets, edges, and vertices
// on negative side of the plane. Calls drawslice.
// slice_list - print coordinates of vertices along a slice.
// "slicer" usage:
// Set slice_a,slice_b,slice_c,slice_d coefficients so
// slice_a*x + slice_b*y + slice_c*z >= slice_d
// is the side you want, and do "slicer".
// output: truncated surface on positive side of plane
// Try not to slice exactly through vertices!!
// Default plane is slice_a := 0, slice_b := 0, slice_c := 1, slice_d := .1
// To mark the vertices and edges created by the current slicing,
// there are a vertex attribute v_timestamp and an edge attribute
// e_timestamp that are set to slice_timestamp, which is incremented
// each time slicer is called.
// Works in torus by rewrapping wrapped edges that would be cut
// so unwrapped part is on positive side of cut plane.
// Slice_list:
// Listing of vertices along the slice, beginning at user-designated vertex.
// If the slice has multiple components, you will have to run separately
// for each component.
// Usage: set startv to the first vertex on the slice and call slice_list
// Output is to stdout, so will usually be redirected, e.g.
// slice_list >>> "slice.dat"
//Set these coefficients for the slicing plane
slice_a := 0;
slice_b := 0;
slice_c := 1;
slice_d := .1;
// Attributes for marking vertices and edges on slice with timestamp
slice_timestamp := 0
define vertex attribute v_timestamp integer
define edge attribute e_timestamp integer
// First put in new edges along slicing plane
drawslice := {
local lambda;
local denom;
local xx1;
local yy1;
local zz1;
local xx2;
local yy2;
local zz2;
slice_timestamp += 1; // marker for this slice
foreach edge ee do
{
xx1 := ee.vertex[1].x;
yy1 := ee.vertex[1].y;
zz1 := ee.vertex[1].z;
xx2 := xx1 + ee.x; // using edge vector in case of torus wrap
yy2 := yy1 + ee.y;
zz2 := zz1 + ee.z;
denom := slice_a*(xx1-xx2)+slice_b*(yy1-yy2)+slice_c*(zz1-zz2);
if ( denom != 0.0 ) then
{
lambda := (slice_d-slice_a*xx2-slice_b*yy2-slice_c*zz2)/denom;
if ( (lambda >= 0) and (lambda <= 1) ) then
{
if torus then
if ee.wrap then
{ if denom > 0 then // tail on positive side
wrap_vertex(ee.vertex[2].id,ee.wrap)
else // head on positive side
wrap_vertex(ee.vertex[1].id,wrap_inverse(ee.wrap));
};
xb := lambda*xx1+(1-lambda)*xx2;
yb := lambda*yy1+(1-lambda)*yy2;
zb := lambda*zz1+(1-lambda)*zz2;
refine ee;
ee.vertex[2].v_timestamp := slice_timestamp;
ee.vertex[2].x := xb;
ee.vertex[2].y := yb;
ee.vertex[2].z := zb;
}
else if torus and ee.wrap then
{ // try wrapping from head
xx2 := ee.vertex[2].x;
yy2 := ee.vertex[2].y;
zz2 := ee.vertex[2].z;
xx1 := xx2 - ee.x; // using edge vector in case of torus wrap
yy1 := yy2 - ee.y;
zz1 := zz2 - ee.z;
denom := slice_a*(xx1-xx2)+slice_b*(yy1-yy2)+slice_c*(zz1-zz2);
if ( denom != 0.0 ) then
{
lambda := (slice_d-slice_a*xx2-slice_b*yy2-slice_c*zz2)/denom;
if ( (lambda >= 0) and (lambda <= 1) ) then
{
if torus then
if ee.wrap then
{ if denom > 0 then // tail on positive side
wrap_vertex(ee.vertex[2].id,ee.wrap)
else // head on positive side
wrap_vertex(ee.vertex[1].id,wrap_inverse(ee.wrap));
};
xb := lambda*xx1+(1-lambda)*xx2;
yb := lambda*yy1+(1-lambda)*yy2;
zb := lambda*zz1+(1-lambda)*zz2;
refine ee;
ee.vertex[2].v_timestamp := slice_timestamp;
ee.vertex[2].x := xb;
ee.vertex[2].y := yb;
ee.vertex[2].z := zb;
}
}
}
} ;
} ;
// mark edges created by slicing
set edge ee e_timestamp min(ee.vertex,v_timestamp);
}
slicer := {
drawslice;
former_autodisplay := (autodisplay);
autodisplay off; // prevent display while dissolving
foreach facet ff where // again, careful of torus wraps
slice_a*(ff.vertex[1].x+ff.edge[1].x/3-ff.edge[3].x/3) +
slice_b*(ff.vertex[1].y+ff.edge[1].y/3-ff.edge[3].y/3) +
slice_c*(ff.vertex[1].z+ff.edge[1].z/3-ff.edge[3].z/3) < slice_d do
{ unset ff frontbody;
unset ff backbody;
dissolve ff;
};
dissolve bodies bbb where sum(bbb.facets,1) == 0;
dissolve edges; // just does bare edges
dissolve vertices; // just does bare vertices
if former_autodisplay then autodisplay on;
}
color_slice := {
foreach facet ff where // again, careful of torus wraps
slice_a*(ff.vertex[1].x+ff.edge[1].x/3-ff.edge[3].x/3) +
slice_b*(ff.vertex[1].y+ff.edge[1].y/3-ff.edge[3].y/3) +
slice_c*(ff.vertex[1].z+ff.edge[1].z/3-ff.edge[3].z/3) < slice_d do
set ff color magenta;
}
// Listing of vertices along the slice, beginning at user-designated vertex.
// If the slice has multiple components, you will have to run separately
// for each component.
// Usage: set startv to the first vertex on the slice and call slice_list
// Output is to stdout, so will usually be redirected, e.g.
// slice_list >>> "slice.dat"
startv := 1
slice_list := {
if vertex[startv].v_timestamp != slice_timestamp then
{ errprintf "slice_list: starting vertex startv is %d, not on latest slice.\n",
startv;
return;
};
thisv := startv;
thisedge := 0;
do
{ // print current vertex coordinates
printf "%20.15f %20.15f %20.15f\n",vertex[thisv].x,vertex[thisv].y,
vertex[thisv].z;
nextedge := 0;
foreach vertex[thisv].edge ee where ee.e_timestamp == slice_timestamp
do { if ee.oid != -thisedge then { nextedge := ee.oid; break; }};
if nextedge == 0 then break; /* done */
thisv := edge[nextedge].vertex[2].id;
thisedge := nextedge;
} while thisv != startv; // done
}
// "slicer" usage:
// Set slice_a,slice_b,slice_c,slice_d coefficients so
// slice_a*x + slice_b*y + slice_c*z >= slice_d
// is the side you want, and do "slicer".
// Default plane is slice_a := 0, slice_b := 0, slice_c := 1, slice_d := .1
evolver-2.30c.dfsg/fe/relaxed.fe 0000644 0001753 0001753 00000001303 11410765113 016755 0 ustar hazelsct hazelsct // relaxed.fe
// Test of relaxed_elastic energy
space_dimension 5 // 2 extra for unstrained reference coordinates
quantity stretchy energy method relaxed_elastic global
quantity stretchy1 info_only method relaxed_elastic1 global
quantity stretchy2 info_only method relaxed_elastic2 global
define facet attribute poisson_ratio real
define vertex attribute ref_coord real[2]
constraint 1 formula: x4 = ref_coord[1]
constraint 2 formula: x5 = ref_coord[2]
vertices
1 0 0 0 0 0 constraint 1,2 ref_coord 0 0
2 1 0 0 1 0 constraint 1,2 ref_coord 1 0
3 0 1 0 1 1 constraint 1,2 ref_coord 0 1
edges
1 1 2
2 2 3
3 3 1
faces
1 1 2 3
read
set facet poisson_ratio 0.8
set facet tension 0.0
evolver-2.30c.dfsg/fe/column.fe 0000644 0001753 0001753 00000007043 11410765113 016635 0 ustar hazelsct hazelsct // column.fe
// Example of calculating forces exerted by a
// column of liquid solder in shape of skewed catenoid.
// All units cgs
parameter RAD = 0.05 // ring radius
parameter ZH = 0.08 // total height
parameter SHIFT = 0.025 // shift
#define SG 8 // specific gravity of solder
#define TENS 460 // surface tension of solder
#define GR 980 // acceleration of gravity
gravity_constant GR
BOUNDARY 1 PARAMETERS 1
X1: RAD*cos(P1)
X2: RAD*sin(P1) + SHIFT
X3: ZH
CONTENT // used to compensate for missing top facets
c1: 0
c2: ZH*x
c3: 0
ENERGY // used to compensate for gravitational energy under top facets
e1: 0
e2: GR*ZH^2/2*x
e3: 0
BOUNDARY 2 PARAMETERS 1
X1: RAD*cos(P1)
X2: RAD*sin(P1)
X3: 0
vertices // given in terms of boundary parameter
1 0.00 boundary 1 fixed
2 pi/3 boundary 1 fixed
3 2*pi/3 boundary 1 fixed
4 pi boundary 1 fixed
5 4*pi/3 boundary 1 fixed
6 5*pi/3 boundary 1 fixed
7 0.00 boundary 2 fixed
8 pi/3 boundary 2 fixed
9 2*pi/3 boundary 2 fixed
10 pi boundary 2 fixed
11 4*pi/3 boundary 2 fixed
12 5*pi/3 boundary 2 fixed
edges
1 1 2 boundary 1 fixed
2 2 3 boundary 1 fixed
3 3 4 boundary 1 fixed
4 4 5 boundary 1 fixed
5 5 6 boundary 1 fixed
6 6 1 boundary 1 fixed
7 7 8 boundary 2 fixed
8 8 9 boundary 2 fixed
9 9 10 boundary 2 fixed
10 10 11 boundary 2 fixed
11 11 12 boundary 2 fixed
12 12 7 boundary 2 fixed
13 1 7
14 2 8
15 3 9
16 4 10
17 5 11
18 6 12
faces
1 -1 13 7 -14 density TENS
2 -2 14 8 -15 density TENS
3 -3 15 9 -16 density TENS
4 -4 16 10 -17 density TENS
5 -5 17 11 -18 density TENS
6 -6 18 12 -13 density TENS
bodies
1 1 2 3 4 5 6 volume 0.00045 density SG
read
// horizontal force on upper pad by central differences
dy := .0001
do_yforce := { oldshift := shift; shift := shift + dy;
set vertex y y+dy*z/zh; // uniform shear
recalc;
energy1 := total_energy -
body[1].pressure*(body[1].volume - body[1].target);
oldshift := shift; shift := shift - 2*dy;
set vertex y y-2*dy*z/zh; // uniform shear
recalc;
energy2 := total_energy -
body[1].pressure*(body[1].volume - body[1].target);
yforce := -(energy1-energy2)/2/dy;
printf "restoring force: %20.15f\n",yforce;
// restore everything
oldshift := shift; shift := shift + dy;
set vertex y y+dy*z/zh; // uniform shear
recalc;
}
// vertical force on upper pad by central differences.
dz := .0001
do_zforce := { oldzh := zh; zh := zh + dz;
set vertex z z+dz*z/oldzh; recalc; // uniform stretch
energy1 := total_energy -
body[1].pressure*(body[1].volume - body[1].target);
oldzh := zh; zh := zh - 2*dz;
set vertex z z-2*dz*z/oldzh; recalc; // uniform stretch
energy2 := total_energy -
body[1].pressure*(body[1].volume - body[1].target);
zforce := -(energy1-energy2)/2/dz;
printf "vertical force: %20.15f\n",zforce;
// restore everything
oldzh := zh; zh := zh + dz;
set vertex z z+dz*z/oldzh; recalc; // uniform stretch
}
// Sample evolution and force calculation
gogo := { u; g 5; r; g 5 ; r; g 5; hessian; hessian;
do_yforce; do_zforce;
}
evolver-2.30c.dfsg/fe/popstr.fe 0000644 0001753 0001753 00000000414 11410765113 016662 0 ustar hazelsct hazelsct // popstr.fe
// evolver string vertex popping test
STRING
vertices
1 0.0 0.0 0.0 fixed
2 1.0 0.0 0.0 fixed
3 1.0 0.0 1.0 fixed
4 0.0 0.0 1.0 fixed
5 0.5 0.0 0.5
edges
1 1 5
2 2 5
3 3 5
4 4 5
read
// Typical evolution
gogo := { o; g 5 }
evolver-2.30c.dfsg/fe/povrays.cmd 0000755 0001753 0001753 00000013547 11410765113 017225 0 ustar hazelsct hazelsct // povrays.cmd
// Surface Evolver command for producing POV-Ray input file.
// Output is to stdout, so redirect to desired file.
// Programmer: Ken Brakke, brakke@susqu.edu, http://www.susqu.edu/brakke
// Like povray.cmd, but with vertex normals for a smooth surface.
// A normal at a vertex of a facet is the average of all adjacent
// facet normals within a certain angle of the original facet normal
// Usage:
// Use the "show edge where ..." command to declare which
// edges are to be depicted as thin cylinders.
// Set "edge_radius" to desired radius of edge cylinders.
// Set "critcos" to critical cosine of angle for facets
// regarded as smoothly joined.
// Run "povray" and redirect to desired file, e.g.
// Enter command: povray >>> "something.pov"
// Run "povrays" with output redirected to a file, e.g.
// Enter command: povrays >>> "something.pov"
edge_radius := 0.003; // adjust this for desired radius of edge cylinders
critcos := 0.8; // criterion for vertex normal averaging.
povrays := {
local ffx,ffy,ffz,ffnorm,vernum,nx,ny,nz,fffx,fffy,fffz,fffnorm;
local costheta,nnorm;
printf "// %s in POV-Ray format.\n\n",datafilename;
printf "light_source { <0,0,300> color rgb <1,1,1> }\n";
printf "light_source { <100,0,0> color rgb <1,1,1> }\n";
printf "camera { location <12,0,0> sky <0,0,1> // right handed \n";
printf " up <0,0,1> right <1.3,0,0> look_at <0,0,0> angle 15 }\n";
printf "background { color <0.3,0.8,1.0> } // light blue\n\n";
printf "// Textures corresponding to Evolver colors\n\n";
printf "#declare t_black = texture { pigment { rgb <0.0,0.0,0.0> }}\n";
printf "#declare t_blue = texture { pigment { rgb <0.0,0.0,1.,> }}\n";
printf "#declare t_green = texture { pigment { rgb <0.0,1.,0.0,> }}\n";
printf "#declare t_cyan = texture { pigment { rgb <0.0,1.,1.,> }}\n";
printf "#declare t_red = texture { pigment { rgb <1.,0.0,0.0,> }}\n";
printf "#declare t_magenta = texture { pigment { rgb <1.,0.0,1.,> }}\n";
printf "#declare t_brown = texture { pigment { rgb <1.,0.5,0.,> }}\n";
printf "#declare t_lightgray = texture { pigment { rgb <.6,.6,.6,> }}\n";
printf "#declare t_darkgray = texture { pigment { rgb <.3,.3,.3,> }}\n";
printf "#declare t_lightblue = texture { pigment { rgb <.3,.8,1.,> }}\n";
printf "#declare t_lightgreen = texture { pigment { rgb <.5,1.,.5,> }}\n";
printf "#declare t_lightcyan = texture { pigment { rgb <.5,1.,1.,> }}\n";
printf "#declare t_lightred = texture { pigment { rgb <1.,.5,.5,> }}\n";
printf "#declare t_lightmagenta = texture { pigment { rgb <1.,.5,1.,> }}\n";
printf "#declare t_yellow = texture { pigment { rgb <1.,1.,.0,> }}\n";
printf "#declare t_white = texture { pigment { rgb <1.,1.,1.,> }}\n";
printf "\n//One overall object.\n";
printf "union {\n";
printf "// All facets in one big mesh object for efficiency.\n";
printf " mesh { \n";
foreach facet ff do {
printf " smooth_triangle { ";
ffx := ff.x; ffy := ff.y; ffz := ff.z;
ffnorm := sqrt(ffx^2 + ffy^2 + ffz^2);
vernum := 1;
while ( vernum <= 3 ) do
{ nx := 0; ny := 0; nz := 0;
foreach ff.vertex[vernum].facet fff do
{ fffx := fff.x; fffy := fff.y; fffz := fff.z;
fffnorm := sqrt(fffx^2 + fffy^2 + fffz^2);
costheta := (fffx*ffx+fffy*ffy+fffz*ffz)/ffnorm/fffnorm;
if ( costheta > critcos ) then
{ nx := nx + fffx/fffnorm;
ny := ny + fffy/fffnorm;
nz := nz + fffz/fffnorm;
}
else if ( costheta < -critcos ) then // in case nonorientable
{ nx := nx - fffx/fffnorm;
ny := ny - fffy/fffnorm;
nz := nz - fffz/fffnorm;
}
};
nnorm := sqrt(nx^2+ny^2+nz^2);
if vernum > 1 then printf ",";
printf "<%f,%f,%f>,<%f,%f,%f>",
ff.vertex[vernum].x,ff.vertex[vernum].y,ff.vertex[vernum].z,
nx/nnorm,ny/nnorm,nz/nnorm;
vernum := vernum + 1;
};
printf " texture {";
if ( ff.color == white ) then printf " t_white "
else if ( ff.color == black ) then printf " t_black "
else if ( ff.color == blue) then printf " t_blue "
else if ( ff.color == green ) then printf " t_green "
else if ( ff.color == cyan ) then printf " t_cyan "
else if ( ff.color == red ) then printf " t_red "
else if ( ff.color == magenta ) then printf " t_magenta "
else if ( ff.color == brown ) then printf " t_brown "
else if ( ff.color == lightgray ) then printf " t_lightgray "
else if ( ff.color == darkgray ) then printf " t_darkgray "
else if ( ff.color == lightblue ) then printf " t_lightblue "
else if ( ff.color == lightgreen ) then printf " t_lightgreen "
else if ( ff.color == lightcyan ) then printf " t_lightcyan "
else if ( ff.color == lightred ) then printf " t_lightred "
else if ( ff.color == lightmagenta ) then printf " t_lightmagenta "
else if ( ff.color == yellow ) then printf " t_yellow ";
printf " } }\n";
};
printf " } // end of mesh object\n";
// Do desired edges
printf "#declare edge_radius = %f;\n",edge_radius;
foreach edge ee where ee.show do
{ printf "cylinder { <%f,%f,%f>,<%f,%f,%f> edge_radius texture { t_black } }\n",
ee.vertex[1].x,ee.vertex[1].y,ee.vertex[1].z,
ee.vertex[2].x,ee.vertex[2].y,ee.vertex[2].z;
};
// Windup
printf "// overall viewing transformation\n";
printf " matrix < %f,%f,%f,\n",
view_matrix[1][1],view_matrix[2][1],view_matrix[3][1];
printf " %f,%f,%f,\n",
view_matrix[1][2],view_matrix[2][2],view_matrix[3][2];
printf " %f,%f,%f,\n",
view_matrix[1][3],view_matrix[2][3],view_matrix[3][3];
printf " %f,%f,%f>\n",
view_matrix[1][4],view_matrix[2][4],view_matrix[3][4];
printf " } // end of all objects\n";
}
evolver-2.30c.dfsg/fe/cmccousin.cmd 0000755 0001753 0001753 00000034312 11410765113 017476 0 ustar hazelsct hazelsct // CMCcousin.cmd
// Programmer: Ken Brakke, brakke@susqu.edu, http://www.susqu.edu/brakke
// A constant mean curvature surface in R^3 has a "cousin" minimal
// surface in S^3, which is isometric to it and has tangent planes
// rotated by 90 degrees. In S^3, the translation is done through
// the quaternion group.
// This representation uses the 4th coordinate as the quaternion
// scalar component, for better mapping between R^3 and S^3 at quaternion unit.
// Datafiles should be set up in 4 dimensions, with S^3 implemented as
// level set constraint x^2 + y^2 + z^2 + w^2 = 1
// Works best if starting edge starte is toward the center of the surface
// rather than on the outside.
// Procedures contained in this file:
// s3_to_r3: Converts minimal surface in S^3 to CMC 1 surface in R^3.
// Remove all constraints and boundaries before invoking.
// r3_to_s3: Converts CMC 1 surface in R^3 to minimal surface in S^3.
// Remove all constraints and boundaries before invoking.
// procedure centralize(integer v_id): translates S^3 so given vertex
// is at (0,0,0,1).
// For converting to adjoint
define vertex attribute newx real [4];
define edge attribute eflag integer;
define edge attribute enewx real [4];
// Angle of Bonnet rotation, degrees
bangle := 90
// unit normal of S^3 facet
define s3points real[3][4] // input
define s3normal real[4] // for return
calc_s3_normal := {
// triple product in R^4
s3normal[1] := s3points[1][2]*(s3points[2][3]*s3points[3][4]
- s3points[2][4]*s3points[3][3])
+ s3points[1][3]*(s3points[2][4]*s3points[3][2]
- s3points[2][2]*s3points[3][4])
+ s3points[1][4]*(s3points[2][2]*s3points[3][3]
- s3points[2][3]*s3points[3][2]);
s3normal[2] := -(s3points[1][1]*(s3points[2][3]*s3points[3][4]
- s3points[2][4]*s3points[3][3])
+ s3points[1][3]*(s3points[2][4]*s3points[3][1]
- s3points[2][1]*s3points[3][4])
+ s3points[1][4]*(s3points[2][1]*s3points[3][3]
- s3points[2][3]*s3points[3][1]));
s3normal[3] := s3points[1][1]*(s3points[2][2]*s3points[3][4]
- s3points[2][4]*s3points[3][2])
+ s3points[1][2]*(s3points[2][4]*s3points[3][1]
- s3points[2][1]*s3points[3][4])
+ s3points[1][4]*(s3points[2][1]*s3points[3][2]
- s3points[2][2]*s3points[3][1]);
s3normal[4] := -(s3points[1][1]*(s3points[2][2]*s3points[3][3]
- s3points[2][3]*s3points[3][2])
+ s3points[1][2]*(s3points[2][3]*s3points[3][1]
- s3points[2][1]*s3points[3][3])
+ s3points[1][3]*(s3points[2][1]*s3points[3][2]
- s3points[2][2]*s3points[3][1]));
mag := sqrt(s3normal[1]^2 + s3normal[2]^2 + s3normal[3]^2 + s3normal[4]^2);
for ( inx := 1 ; inx < 4 ; inx += 1 )
s3normal[inx] /= mag;
}
// Swaps conjugate sets of coordinates.
flip := {
foreach vertex vv do
{ tmp := vv.x; vv.x := vv.newx[1]; vv.newx[1] := tmp;
tmp := vv.y; vv.y := vv.newx[2]; vv.newx[2] := tmp;
tmp := vv.z; vv.z := vv.newx[3]; vv.newx[3] := tmp;
tmp := vv.w; vv.w := vv.newx[4]; vv.newx[4] := tmp;
}
}
starte := 0 // user should set starte to set origin of adjoint.
define rn real[3][4];
define emid real[3][4];
calc_s3_to_r3 := {
set edge eflag 0;
if starte == 0 then
foreach edge ee do { starte := ee.id; break; }; // just to get starter
edge[starte].enewx[1] := 0;
edge[starte].enewx[2] := 0;
edge[starte].enewx[3] := 0;
edge[starte].eflag := 1;
bs := sin(bangle*pi/180);
bc := cos(bangle*pi/180);
ecount := 1;
endflag := 0;
loopcount := 1;
while ( !endflag ) do
{ endflag := 1;
foreach facet ff do
{ enum := 1;
while ( enum <= 5 ) do
{ thise := (enum imod 3) + 1;
nexte := ((enum+1) imod 3) + 1;
othere := ((enum+2) imod 3) + 1;
if ( ff.edge[thise].eflag>=loopcount and !ff.edge[nexte].eflag ) then
{ // transform this facet
// normal in S3
for ( inx := 1 ; inx <= 4 ; inx += 1 )
for ( vnx := 1 ; vnx <= 3 ; vnx += 1 )
s3points[vnx][inx] := ff.vertex[vnx].x[inx];
calc_s3_normal;
// edge midpoints in S3
for ( enx := 1 ; enx <= 3 ; enx += 1 )
{ for ( inx := 1 ; inx <= 4 ; inx += 1 )
emid[enx][inx] := avg(ff.edge[enx].vertex,x[inx]);
mag := sqrt(emid[enx][1]^2 + emid[enx][2]^2 + emid[enx][3]^2
+ emid[enx][4]^2);
for ( inx := 1 ; inx <= 4 ; inx += 1 )
emid[enx][inx] /= mag;
// Use inverse quaternion of each edge midpoint to convert
// common normal to R3 normal
rn[enx][1] := emid[enx][4]*s3normal[1] - s3normal[4]*emid[enx][1]
- (emid[enx][2]*s3normal[3] - emid[enx][3]*s3normal[2]);
rn[enx][2] := emid[enx][4]*s3normal[2] - s3normal[4]*emid[enx][2]
- (emid[enx][3]*s3normal[1] - emid[enx][1]*s3normal[3]);
rn[enx][3] := emid[enx][4]*s3normal[3] - s3normal[4]*emid[enx][3]
- (emid[enx][1]*s3normal[2] - emid[enx][2]*s3normal[1]);
};
for ( inx := 1 ; inx <= 3 ; inx += 1 )
ff.edge[nexte].enewx[inx] :=
ff.edge[thise].enewx[inx] + rn[nexte][inx] - rn[thise][inx];
ff.edge[nexte].eflag := loopcount+1;
endflag := 0;
ecount += 1;
};
enum += 1;
}; // end while
};
if !quiet then printf "%g edges done.\n",ecount;
loopcount += 1;
};
set vertex newx[1] 0;
set vertex newx[2] 0;
set vertex newx[3] 0;
foreach facet ff do
{ // extend center facet to original vertex; can't simply average
// midedge vertices around an original vertex since that doesn't
// work for vertices on the boundary.
vva := 1; while ( vva <= 3 ) do
{ vvb := vva==3 ? 1 : vva+1;
vvc := vva==1 ? 3 : vva-1;
kk := 1; while ( kk <= 3 ) do
{
ff.vertex[vva].newx[kk] += ff.edge[vva].enewx[kk]
- ff.edge[vvb].enewx[kk] + ff.edge[vvc].enewx[kk];
kk += 1;
};
vva += 1;
}
};
foreach vertex vv do
{
nbrs := sum(vv.facet, 1);
if ( nbrs != 0 ) then
{ vv.newx[1] /= nbrs;
vv.newx[2] /= nbrs;
vv.newx[3] /= nbrs;
vv.newx[4] := 0;
};
};
} // end calc_s3_to_r3
// try using average normal at edge midpoints
calc_s3_to_r3_a := {
define facet attribute snormal real[4];
define nmid real[4][4];
set edge eflag 0;
if starte == 0 then
foreach edge ee do { starte := ee.id; break; }; // just to get starter
edge[starte].enewx[1] := 0;
edge[starte].enewx[2] := 0;
edge[starte].enewx[3] := 0;
edge[starte].eflag := 1;
foreach facet ff do
{ for ( inx := 1 ; inx <= 4 ; inx += 1 )
for ( vnx := 1 ; vnx <= 3 ; vnx += 1 )
s3points[vnx][inx] := ff.vertex[vnx].x[inx];
calc_s3_normal;
for ( inx := 1 ; inx <= 4 ; inx += 1 )
ff.snormal[inx] := s3normal[inx];
};
bs := sin(bangle*pi/180);
bc := cos(bangle*pi/180);
ecount := 1;
endflag := 0;
loopcount := 1;
while ( !endflag ) do
{ endflag := 1;
foreach facet ff do
{ enum := 1;
while ( enum <= 5 ) do
{ thise := (enum imod 3) + 1;
nexte := ((enum+1) imod 3) + 1;
othere := ((enum+2) imod 3) + 1;
if ( ff.edge[thise].eflag>=loopcount and !ff.edge[nexte].eflag ) then
{ // transform this facet
// edge midpoints in S3
for ( enx := 1 ; enx <= 3 ; enx += 1 )
{ for ( inx := 1 ; inx <= 4 ; inx += 1 )
{ emid[enx][inx] := avg(ff.edge[enx].vertex,x[inx]);
nmid[enx][inx] := avg(ff.edge[enx].facet,snormal[inx]);
};
mag := sqrt(emid[enx][1]^2 + emid[enx][2]^2 + emid[enx][3]^2
+ emid[enx][4]^2);
nmag := sqrt(nmid[enx][1]^2 + nmid[enx][2]^2 + nmid[enx][3]^2
+ nmid[enx][4]^2);
for ( inx := 1 ; inx <= 4 ; inx += 1 )
{ emid[enx][inx] /= mag;
nmid[enx][inx] /= nmag;
};
// Use inverse quaternion of each edge midpoint to convert
// common normal to R3 normal
rn[enx][1] := emid[enx][4]*nmid[enx][1] - nmid[enx][4]*emid[enx][1]
- (emid[enx][2]*nmid[enx][3] - emid[enx][3]*nmid[enx][2]);
rn[enx][2] := emid[enx][4]*nmid[enx][2] - nmid[enx][4]*emid[enx][2]
- (emid[enx][3]*nmid[enx][1] - emid[enx][1]*nmid[enx][3]);
rn[enx][3] := emid[enx][4]*nmid[enx][3] - nmid[enx][4]*emid[enx][3]
- (emid[enx][1]*nmid[enx][2] - emid[enx][2]*nmid[enx][1]);
};
for ( inx := 1 ; inx <= 3 ; inx += 1 )
ff.edge[nexte].enewx[inx] :=
ff.edge[thise].enewx[inx] + rn[nexte][inx] - rn[thise][inx];
ff.edge[nexte].eflag := loopcount+1;
endflag := 0;
ecount += 1;
};
enum += 1;
}; // end while
};
if !quiet then printf "%g edges done.\n",ecount;
loopcount += 1;
};
set vertex newx[1] 0;
set vertex newx[2] 0;
set vertex newx[3] 0;
foreach facet ff do
{ // extend center facet to original vertex; can't simply average
// midedge vertices around an original vertex since that doesn't
// work for vertices on the boundary.
vva := 1; while ( vva <= 3 ) do
{ vvb := vva==3 ? 1 : vva+1;
vvc := vva==1 ? 3 : vva-1;
kk := 1; while ( kk <= 3 ) do
{
ff.vertex[vva].newx[kk] += ff.edge[vva].enewx[kk]
- ff.edge[vvb].enewx[kk] + ff.edge[vvc].enewx[kk];
kk += 1;
};
vva += 1;
}
};
foreach vertex vv do
{
nbrs := sum(vv.facet, 1);
if ( nbrs != 0 ) then
{ vv.newx[1] /= nbrs;
vv.newx[2] /= nbrs;
vv.newx[3] /= nbrs;
vv.newx[4] := 0;
};
};
} // end calc_s3_to_r3
calc_r3_to_s3 := {
set edge eflag 0;
if starte == 0 then
foreach edge ee do { starte := ee.id; break; }; // just to get starter
edge[starte].enewx[1] := 0;
edge[starte].enewx[2] := 0;
edge[starte].enewx[3] := 0;
edge[starte].enewx[4] := 1;
edge[starte].eflag := 1;
bs := sin(bangle*pi/180);
bc := cos(bangle*pi/180);
ecount := 1;
endflag := 0;
loopcount := 1;
while ( !endflag ) do
{ endflag := 1;
foreach facet ff do
{ enum := 1;
while ( enum <= 5 ) do
{ thise := (enum imod 3) + 1;
nexte := ((enum+1) imod 3) + 1;
othere := ((enum+2) imod 3) + 1;
if ( ff.edge[thise].eflag>=loopcount and !ff.edge[nexte].eflag ) then
{ // facet unit normal
nx := ff.x;
ny := ff.y;
nz := ff.z;
norm := sqrt(nx^2+ny^2+nz^2);
nx := nx/norm; ny := ny/norm; nz := nz/norm;
// vector from thise to nexte
vx := -ff.edge[othere].x/2;
vy := -ff.edge[othere].y/2;
vz := -ff.edge[othere].z/2;
// rotate 90 degrees about normal (using cross product)
qx := -(ny*vz - nz*vy);
qy := -(nz*vx - nx*vz);
qz := -(nx*vy - ny*vx);
qw := sqrt(1 - (qx^2 + qy^2 + qz^2));
// quaternion multiplication by position of thise midpoint
tx := ff.edge[thise].enewx[1];
ty := ff.edge[thise].enewx[2];
tz := ff.edge[thise].enewx[3];
tw := ff.edge[thise].enewx[4];
ff.edge[nexte].enewx[1] := tw*qx + qw*tx + (ty*qz - tz*qy);
ff.edge[nexte].enewx[2] := tw*qy + qw*ty + (tz*qx - tx*qz);
ff.edge[nexte].enewx[3] := tw*qz + qw*tz + (tx*qy - ty*qx);
ff.edge[nexte].enewx[4] := tw*qw - (tx*qx + ty*qy + tz*qz);
ff.edge[nexte].eflag := loopcount+1;
endflag := 0;
ecount += 1;
};
enum += 1;
}; // end while
};
if !quiet then printf "%g edges done.\n",ecount;
loopcount += 1;
};
set vertex newx[1] 0;
set vertex newx[2] 0;
set vertex newx[3] 0;
set vertex newx[4] 0;
foreach facet ff do
{ // extend center facet to original vertex; can't simply average
// midedge vertices around an original vertex since that doesn't
// work for vertices on the boundary.
for ( vva := 1; vva <= 3 ; vva += 1 )
{ vvb := vva==3 ? 1 : vva+1;
vvc := vva==1 ? 3 : vva-1;
for ( kk := 1; kk <= 4 ; kk += 1 )
{
ff.vertex[vva].newx[kk] += ff.edge[vva].enewx[kk]
- ff.edge[vvb].enewx[kk] + ff.edge[vvc].enewx[kk];
};
};
};
foreach vertex vv do
{
nbrs := sum(vv.facet, 1);
if ( nbrs != 0 ) then
{ vv.newx[1] /= nbrs;
vv.newx[2] /= nbrs;
vv.newx[3] /= nbrs;
vv.newx[4] /= nbrs;
};
};
} // end calc_r3_to_s3
s3_to_r3 := {
foreach vertex vv do
if vv.__v_constraint_list[1] != 0 then
{ errprintf "s3_to_r3 error: vertex %d is still on a constraint.\n",
vv.id;
return;
};
autodisplay_state := (autodisplay);
autodisplay off;
calc_s3_to_r3;
flip;
if ( autodisplay_state ) then autodisplay;
}
r3_to_s3 := {
foreach vertex vv do
if vv.__v_constraint_list[1] != 0 then
{ errprintf "s3_to_r3 error: vertex %d is still on a constraint.\n",
vv.id;
return;
};
autodisplay_state := (autodisplay);
autodisplay off;
calc_r3_to_s3;
flip;
if ( autodisplay_state ) then autodisplay;
}
// Utility function for translating surface in sphere to get
// desired vertex at identity element (0,0,0,1).
procedure centralize ( integer v_id ) {
ax := vertex[v_id].x;
ay := vertex[v_id].y;
az := vertex[v_id].z;
aw := vertex[v_id].w;
foreach vertex vv do {
vx := vv.x;
vy := vv.y;
vz := vv.z;
vw := vv.w;
vv.x := aw*vx - vw*ax - (ay*vz - az*vy);
vv.y := aw*vy - vw*ay - (az*vx - ax*vz);
vv.z := aw*vz - vw*az - (ax*vy - ay*vx);
vv.w := aw*vw + ax*vx + ay*vy + az*vz;
};
}
evolver-2.30c.dfsg/fe/order.cmd 0000755 0001753 0001753 00000001634 11410765113 016627 0 ustar hazelsct hazelsct // order.cmd
// Evolver command to number string-model vertices consecutively.
// Result is order number in vertex extra attribute 'number'.
// Programmer: Ken Brakke, brakke@susqu.edu, http://www.susqu.edu/brakke
// Usage: order
define vertex attribute number integer
order := {
local ecount,e_id,first_e,v_id,newv_id,newe_id;
ecount := 0; // for safety
// get starting edge, since can't assume edge[1] exists
foreach edge do { e_id := id; break; };
first_e := e_id;
v_id := edge[e_id].vertex[1].id;
// follow connected edges
do
{ set vertex[v_id] number ecount+1;
foreach edge[e_id].vertex vv do
{ if ( vv.id != v_id ) then
{ newv_id := vv.id;
foreach vv.edge ee do
if ee.id != e_id then newe_id := ee.id
}
};
e_id := newe_id; v_id := newv_id;
ecount := ecount + 1;
} while ( (e_id != first_e) and (ecount <= edge_count) )
}
evolver-2.30c.dfsg/fe/symtest.fe 0000644 0001753 0001753 00000003036 11410765113 017046 0 ustar hazelsct hazelsct // symtest.fe
// test of quotient space mechanism
// same surface as in twointor.fe
// Two Kelvin tetrakaidecahedra in a torus.
SYMMETRY_GROUP "torus" // same name as in quotient.c
vertices
1 0.50 0.00 0.75
2 0.25 0.00 0.50
3 0.00 0.25 0.50
4 0.75 0.00 0.50
5 0.00 0.50 0.75
6 0.50 0.00 0.25
7 0.00 0.75 0.50
8 0.50 0.25 0.00
9 0.25 0.50 0.00
10 0.00 0.50 0.25
11 0.50 0.75 0.00
12 0.75 0.50 0.00
// wrap codes for group elements using scheme in quotient.c
#define XWRAP 1
#define XWRAPNEG 31
#define YWRAP 64
#define YWRAPNEG 31*64
#define ZWRAP 64*64
#define ZWRAPNEG 31*64*64
edges /* with torus wrap symbols */
1 1 2
2 2 3
3 1 4
4 3 5
5 2 6
6 2 7 wrap YWRAPNEG
7 1 8 wrap ZWRAP
8 4 6
9 5 9 wrap ZWRAP
10 3 10
11 3 4 wrap XWRAPNEG
12 6 8
13 6 11 wrap YWRAPNEG
14 7 4 wrap XWRAPNEG+YWRAP
15 8 12
16 9 8
17 9 11
18 10 7
19 11 1 wrap YWRAP+ZWRAPNEG
20 12 5 wrap XWRAP+ZWRAPNEG
21 5 7
22 11 12
23 10 12 wrap XWRAPNEG
24 9 10
faces
1 1 2 4 9 16 -7
2 -2 5 12 -16 24 -10
3 -4 10 18 -21
4 7 15 20 -4 11 -3
5 -1 3 8 -5
6 6 14 -11 -2
7 5 13 -17 24 18 -6
8 -12 13 19 7
9 -16 17 22 -15
10 -10 11 8 12 15 -23
11 -21 9 17 19 1 6
12 -14 -18 23 -22 -13 -8
13 -24 -9 -20 -23
14 -19 22 20 21 14 -3
bodies
1 -1 -2 -3 -4 -5 9 7 11 -9 10 12 5 14 3 // volume 0.500
2 2 -6 -7 8 -10 -12 -11 -13 1 13 -14 6 4 -8 // volume 0.500
evolver-2.30c.dfsg/fe/OCTA.WLF 0000644 0001753 0001753 00000000146 11410765113 016121 0 ustar hazelsct hazelsct 0 0 1
0 0 -1
0.707 0.707 0
-0.707 0.707 0
0.707 -0.707 0
-0.707 -0.707 0
evolver-2.30c.dfsg/fe/slice.cmd 0000755 0001753 0001753 00000003630 11410765113 016611 0 ustar hazelsct hazelsct // slice.cmd --- Calculate length of intersection of plane with surface.
// Does not modify surface.
// plane eq: aa*x + bb*y + cc*z = dd
// output: prints length of slice, and area inside slice.
// Note all area inside slice is counted as positive!
// Try not to slice exactly through vertices!!
// Programmer: Ken Brakke, brakke@susqu.edu, http://www.susqu.edu/brakke
// Usage: Set plane coefficients, then do "slice".
// Results: Intersection length printed out, left in variable lensum.
aa := 0; bb := 0; cc := 1; dd := .1; // set these for desired plane
slice := {
local any,xx1,yy1,zz1,xx2,yy2,zz2;
local denom,lambda,zaa,zbb,darea;
local xa,ya,za,xb,yb,zb;
lensum := 0; areasum := 0;
foreach facet ff do
{ any := 0;
foreach ff.edge ee do
{
xx1 := ee.vertex[1].x;
yy1 := ee.vertex[1].y;
zz1 := ee.vertex[1].z;
xx2 := ee.vertex[2].x;
yy2 := ee.vertex[2].y;
zz2 := ee.vertex[2].z;
denom := aa*(xx1-xx2)+bb*(yy1-yy2)+cc*(zz1-zz2);
if ( denom != 0.0 ) then
{
lambda := (dd-aa*xx2-bb*yy2-cc*zz2)/denom;
if ( (lambda >= 0) and (lambda <= 1) ) then
{
xa := xb; ya := yb; za := zb;
xb := lambda*xx1+(1-lambda)*xx2;
yb := lambda*yy1+(1-lambda)*yy2;
zb := lambda*zz1+(1-lambda)*zz2;
any := any+1;
}
}
} ;
if any == 2 then
{
dx := xa-xb; dy := ya-yb; dz := za - zb;
lensum := lensum + sqrt(dx^2+dy^2+dz^2);
zaa := za - dd/cc; zbb := zb - dd/cc;
darea := sqrt((ya*zbb-yb*zaa)^2+(zaa*xb-zbb*xa)^2+(xa*yb-ya*xb)^2);
areasum := areasum + darea/2;
}
};
printf "Circumference: %18.15g Area: %18.15g\n",lensum,areasum;
} // end slice
evolver-2.30c.dfsg/fe/qmound.fe 0000644 0001753 0001753 00000004127 11410765113 016643 0 ustar hazelsct hazelsct // qmound.fe
// Evolver data for drop of prescribed volume sitting on plane with gravity.
// Contact angle with plane can be varied.
// Volume constraint implemented as quantity constraint
PARAMETER angle = 90 // interior angle between plane and surface, degrees
#define T (-cos(angle*pi/180)) // virtual tension of facet on plane
quantity vol fixed = 1 method facet_vector_integral global // is volume
vector_integrand:
q1: 0
q2: 0
q3: z
constraint 1 /* the table top */
formula: x3 = 0
energy: // for contact angle
e1: -T*y
e2: 0
e3: 0
vertices
1 0.0 0.0 0.0 constraint 1 /* 4 vertices on plane */
2 1.0 0.0 0.0 constraint 1
3 1.0 1.0 0.0 constraint 1
4 0.0 1.0 0.0 constraint 1
5 0.0 0.0 1.0
6 1.0 0.0 1.0
7 1.0 1.0 1.0
8 0.0 1.0 1.0
9 2.0 2.0 0.0 fixed /* for table top */
10 2.0 -1.0 0.0 fixed
11 -1.0 -1.0 0.0 fixed
12 -1.0 2.0 0.0 fixed
edges /* given by endpoints and attribute */
1 1 2 constraint 1 /* 4 edges on plane */
2 2 3 constraint 1
3 3 4 constraint 1
4 4 1 constraint 1
5 5 6
6 6 7
7 7 8
8 8 5
9 1 5
10 2 6
11 3 7
12 4 8
13 9 10 fixed /* for table top */
14 10 11 fixed
15 11 12 fixed
16 12 9 fixed
faces /* given by oriented edge loop */
1 1 10 -5 -9
2 2 11 -6 -10
3 3 12 -7 -11
4 4 9 -8 -12
5 5 6 7 8
7 13 14 15 16 density 0 fixed /* table top for display */
bodies /* one body, defined by its oriented faces */
1 1 2 3 4 5 density 1
read
re := {refine edges where on_constraint 1 }
// Typical evolution
gogo := { re; g 5; r; g 5; r; g 5; hessian; hessian; }
// Evolution with 45 degree contact angle
gogo2 := { angle := 45; re; g 5; V;V; r; g 5; V;V; r; g 5; hessian; hessian; }
// Evolution with 90 contact and high gravity
gogo3 := { angle := 90; G 5; re; g 5; r; g 5; r; g 5; hessian; hessian; }
// Evolution with 90 contact and negative gravity, i.e. pendant drop
gogo4 := { angle := 90; G -2; re; g 5; r; g 5; r; g 5; hessian; hessian; }
// Pendant drop falling off ceiling
gogo5 := { angle := 90; G -5; re; g 10; t .1; unset vertex constraint 1; g 3; }
evolver-2.30c.dfsg/fe/tuber.cmd 0000755 0001753 0001753 00000014153 11410765113 016635 0 ustar hazelsct hazelsct // tuber.cmd
// Surface Evolver command to put tubes around certain edges, for more
// reliable display of chosen edges. Note that this procedure does
// modify the current surface, rather than write a datafile.
// Usage: Define the "intube" edge attribute to be 1 for the edges
// you want tubed, and call "tuber" with appropriate parameters, i.e.
// Enter command: set edge intube 0
// Enter command: set edge intube 1 where on_constraint 1
// Enter command: tuber(0.01,4,1)
// Programmer: Ken Brakke, brakke@susqu.edu, http://www.susqu.edu/brakke
define edge attribute intube integer // set positive if want tube
procedure tuber (real tube_radius, // radius of tube
integer tube_sides, // how many sides on each tube, >= 3
integer tube_caps // 0 for no caps, 1 for cone caps
)
{
local ax,ay,az,bx,by,bz,mag,elength,tailcapv,headcapv,t_angle,vv1,ww1;
local ee1,start_tailcape,start_headcape,prev_tailcape,prev_headcape;
local vstart,wstart,starte,inx,vv2,ww2,ee2,vend,wend,diag,newf;
local tailcape,headcape;
// Some parameter checking
if tube_sides < 3 then tube_sides := 3;
if tube_radius <= 0 then
{ errprintf "tuber: tube_radius is %f; must be positive.\n",tube_radius;
return;
};
// Now the tubes.
foreach edge ee where intube > 0 do
{
// find two orthogonal directions to edge; if possible,
// one along adjacent facet
if ee.valence > 0 then
{ ax := ee.facet[1].x;
ay := ee.facet[1].y;
az := ee.facet[1].z;
}
else
{ if abs(ee.x) < abs(ee.y) and abs(ee.x) < abs(ee.z) then
{ ax := 1; ay := 0; az := 0;}
else if abs(ee.y) < abs(ee.z) then
{ ax := 0; ay := 1; az := 0; }
else
{ ax := 0; ay := 0; az := 1; };
};
bx := ay*ee.z - az*ee.y;
by := az*ee.x - ax*ee.z;
bz := ax*ee.y - ay*ee.x;
ax := by*ee.z - bz*ee.y;
ay := bz*ee.x - bx*ee.z;
az := bx*ee.y - by*ee.x;
// normalize to radius
mag := sqrt(ax^2+ay^2+az^2);
if mag <= 0 then continue;
ax *= tube_radius/mag;
ay *= tube_radius/mag;
az *= tube_radius/mag;
mag := sqrt(bx^2+by^2+bz^2);
if mag <= 0 then continue;
bx *= tube_radius/mag;
by *= tube_radius/mag;
bz *= tube_radius/mag;
// Tube cap tips, if wanted
if tube_caps then
{ elength := ee.length;
tailcapv := new_vertex(ee.vertex[1].x - ee.x/elength*tube_radius,
ee.vertex[1].y - ee.y/elength*tube_radius,
ee.vertex[1].z - ee.z/elength*tube_radius);
headcapv := new_vertex(ee.vertex[1].x + ee.x + ee.x/elength*tube_radius,
ee.vertex[1].y + ee.y + ee.y/elength*tube_radius,
ee.vertex[1].z + ee.z + ee.z/elength*tube_radius);
fix vertex[tailcapv];
fix vertex[headcapv];
};
// Construct tubes
t_angle := 2*pi/tube_sides;
vv1 := new_vertex(ee.vertex[1].x+ax*cos(0*t_angle)+bx*sin(0*t_angle),
ee.vertex[1].y+ay*cos(0*t_angle)+by*sin(0*t_angle),
ee.vertex[1].z+az*cos(0*t_angle)+bz*sin(0*t_angle));
ww1 := new_vertex(ee.vertex[1].x+ee.x+ax*cos(0*t_angle)+bx*sin(0*t_angle),
ee.vertex[1].y+ee.y+ay*cos(0*t_angle)+by*sin(0*t_angle),
ee.vertex[1].z+ee.z+az*cos(0*t_angle)+bz*sin(0*t_angle));
fix vertex[vv1];
fix vertex[ww1];
ee1 := new_edge(vv1,ww1);
edge[ee1].color := ee.color;
if tube_caps then
{ start_tailcape := new_edge(tailcapv,vv1);
start_headcape := new_edge(ww1,headcapv);
edge[start_tailcape].color := ee.color;
edge[start_headcape].color := ee.color;
prev_tailcape := start_tailcape;
prev_headcape := start_headcape;
};
vstart := vv1; wstart := ww1; starte := ee1;
for ( inx := 1 ; inx <= tube_sides ; inx += 1 )
{
if inx == tube_sides then
{ vv2 := vstart; ww2 := wstart; ee2 := starte; }
else
{ vv2 := new_vertex(ee.vertex[1].x+ax*cos(inx*t_angle)+bx*sin(inx*t_angle),
ee.vertex[1].y+ay*cos(inx*t_angle)+by*sin(inx*t_angle),
ee.vertex[1].z+az*cos(inx*t_angle)+bz*sin(inx*t_angle));
ww2 := new_vertex(ee.vertex[1].x+ee.x+ax*cos(inx*t_angle)+bx*sin(inx*t_angle),
ee.vertex[1].y+ee.y+ay*cos(inx*t_angle)+by*sin(inx*t_angle),
ee.vertex[1].z+ee.z+az*cos(inx*t_angle)+bz*sin(inx*t_angle));
ee2 := new_edge(vv2,ww2);
edge[ee2].color := ee.color;
};
vend := new_edge(vv1,vv2);
wend := new_edge(ww1,ww2);
diag := new_edge(vv2,ww1);
edge[vend].color := ee.color;
edge[wend].color := ee.color;
edge[diag].color := ee.color;
set edge[vend] no_refine;
set edge[wend] no_refine;
set edge[diag] no_refine;
fix edge[vend];
fix edge[wend];
fix edge[diag];
newf := new_facet(vend,diag,-ee1);
set facet[newf] color ee.color;
fix facet[newf];
set facet[newf] no_refine;
set facet[newf] tension 0;
newf := new_facet(ee2,-wend,-diag);
set facet[newf] color ee.color;
fix facet[newf];
set facet[newf] no_refine;
set facet[newf] tension 0;
if tube_caps then
{ if inx == tube_sides then
{ tailcape := start_tailcape;
headcape := start_headcape;
}
else
{ tailcape := new_edge(tailcapv,vv2);
headcape := new_edge(ww2,headcapv);
edge[tailcape].color := ee.color;
edge[headcape].color := ee.color;
};
fix edge[tailcape];
fix edge[headcape];
newf := new_facet(tailcape,-vend,-prev_tailcape);
set facet[newf] color ee.color;
fix facet[newf];
set facet[newf] no_refine;
set facet[newf] tension 0;
newf := new_facet(headcape,-prev_headcape,wend);
set facet[newf] color ee.color;
fix facet[newf];
set facet[newf] no_refine;
set facet[newf] tension 0;
prev_tailcape := tailcape;
prev_headcape := headcape;
};
vv1 := vv2; ww1 := ww2; ee1 := ee2;
}
}
} // end tuber()
evolver-2.30c.dfsg/fe/cat.fe 0000644 0001753 0001753 00000004471 11410765113 016111 0 ustar hazelsct hazelsct // cat.fe
// Evolver data for catenoid.
PARAMETER RMAX = 1.5088795 // minimum radius for height
PARAMETER ZMAX = 1.0
boundary 1 parameters 1 // upper ring
x1: RMAX * cos(p1)
x2: RMAX * sin(p1)
x3: ZMAX
boundary 2 parameters 1 // lower ring
x1: RMAX * cos(p1)
x2: RMAX * sin(p1)
x3: -ZMAX
vertices // given in terms of boundary parameter
1 0.00 boundary 1 fixed
2 pi/3 boundary 1 fixed
3 2*pi/3 boundary 1 fixed
4 pi boundary 1 fixed
5 4*pi/3 boundary 1 fixed
6 5*pi/3 boundary 1 fixed
7 0.00 boundary 2 fixed
8 pi/3 boundary 2 fixed
9 2*pi/3 boundary 2 fixed
10 pi boundary 2 fixed
11 4*pi/3 boundary 2 fixed
12 5*pi/3 boundary 2 fixed
edges
1 1 2 boundary 1 fixed
2 2 3 boundary 1 fixed
3 3 4 boundary 1 fixed
4 4 5 boundary 1 fixed
5 5 6 boundary 1 fixed
6 6 1 boundary 1 fixed
7 7 8 boundary 2 fixed
8 8 9 boundary 2 fixed
9 9 10 boundary 2 fixed
10 10 11 boundary 2 fixed
11 11 12 boundary 2 fixed
12 12 7 boundary 2 fixed
13 1 7
14 2 8
15 3 9
16 4 10
17 5 11
18 6 12
faces
1 1 14 -7 -13
2 2 15 -8 -14
3 3 16 -9 -15
4 4 17 -10 -16
5 5 18 -11 -17
6 6 13 -12 -18
read
// Evolution to collapse and pop neck, as in Manual tutorial
gogo := { r; u; g 120; t .05; o; g 5; }
// Demonstrating saddle point due to triangulation arrangement.
// First setting parameters to stable values.
gogo2 := { rmax := 1; zmax := 0.55; recalc;
g; u; r; g 50; // at this point have nearly a saddle point
g 200; // triangulation twists around to lower energy
}
// Faster version of the above using conjugate gradient
gogo3 := { rmax := 1; zmax := 0.55; recalc;
g; u; r; U; g 25; // at this point have nearly a saddle point
g 35;
}
// High accuracy evolution, using higher-order Lagrange elements.
gogo4 := { u; zmax := 0.55; rmax := cosh(zmax); recalc;
r; g 5; hessian;
r; g 5; hessian;
lagrange 2; g 5; hessian;
lagrange 4; g 5; hessian;
lagrange 6; g 5; hessian;
lagrange 8; g 5; hessian;
true_area := 2*pi*(zmax + 0.5*sinh(2*zmax));
printf"Difference from true area: %g\n",total_area - true_area;
}
evolver-2.30c.dfsg/fe/gaussmap.cmd 0000755 0001753 0001753 00000004434 11410765113 017335 0 ustar hazelsct hazelsct // gaussmap.cmd
// Converts each vertex coordinate to unit normal.
// No vertices should be on constraints or fixed.
// Saves original coordinates so "revert" restores original surface.
// Before running "gaussmap", vertices should be freed from all
// constraints and boundaries.
// Programmer: Ken Brakke, brakke@susqu.edu, http://www.susqu.edu/brakke
// Usage: gaussmap
define vertex attribute gaussx real[3]
define vertex attribute oldx real[3]
gaussmap := {
foreach vertex vv do
{ local connum;
connum := 1;
do { unset vv constraint connum; connum += 1; }
while ( connum < 30 );
vv.oldx[1] := vv.x[1];
vv.oldx[2] := vv.x[2];
vv.oldx[3] := vv.x[3];
vv.gaussx[1] := vv.vertexnormal[1];
vv.gaussx[2] := vv.vertexnormal[2];
vv.gaussx[3] := vv.vertexnormal[3];
};
set vertex x gaussx[1];
set vertex y gaussx[2];
set vertex z gaussx[3];
}
revert := {
set vertex x oldx[1];
set vertex y oldx[2];
set vertex z oldx[3];
}
// Command to find spherical area of gauss map, Lagrange model
calc_gaussarea := {
local jnx, jnxx;
if quadratic then lagrange 2;
gaussarea := 0;
jnx := 2;
jnxx := 3;
foreach facet ff do
{ local angle_a, angle_b, angle_c;
angle_a := asin(sqrt(
(ff.vertex[1].vertexnormal[1]-ff.vertex[jnx].vertexnormal[1])^2
+(ff.vertex[1].vertexnormal[2]-ff.vertex[jnx].vertexnormal[2])^2
+(ff.vertex[1].vertexnormal[3]-ff.vertex[jnx].vertexnormal[3])^2)/2);
angle_b := asin(sqrt(
(ff.vertex[jnxx].vertexnormal[1]-ff.vertex[jnx].vertexnormal[1])^2
+(ff.vertex[jnxx].vertexnormal[2]-ff.vertex[jnx].vertexnormal[2])^2
+(ff.vertex[jnxx].vertexnormal[3]-ff.vertex[jnx].vertexnormal[3])^2)/2);
angle_c := asin(sqrt(
(ff.vertex[jnxx].vertexnormal[1]-ff.vertex[1].vertexnormal[1])^2
+(ff.vertex[jnxx].vertexnormal[2]-ff.vertex[1].vertexnormal[2])^2
+(ff.vertex[jnxx].vertexnormal[3]-ff.vertex[1].vertexnormal[3])^2)/2);
gaussarea += 4*atan(sqrt(tan((angle_a+angle_b+angle_c)/2)
*tan((angle_a+angle_b-angle_c)/2)
*tan((angle_a-angle_b+angle_c)/2)
*tan((-angle_a+angle_b+angle_c)/2)));
};
printf "Gauss map area: %18.15f or %18.15f*pi\n",gaussarea,gaussarea/pi;
}
evolver-2.30c.dfsg/fe/quad.fe 0000644 0001753 0001753 00000000455 11410765113 016272 0 ustar hazelsct hazelsct // quad.fe
// simple skew quadrilateral
vertices
1 0 0 1 fixed
2 2 0 0 fixed
3 2 2 1 fixed
4 0 2 0 fixed
edges
1 1 2 fixed
2 2 3 fixed
3 3 4 fixed
4 4 1 fixed
faces
1 1 2 3 4
read
// Typical evolution
gogo := { r; g 5; r; g 5; r; g 5; hessian; hessian; }
evolver-2.30c.dfsg/fe/equi.cmd 0000755 0001753 0001753 00000001603 11410765113 016453 0 ustar hazelsct hazelsct // equi.cmd -- to color edges green subject to equiangulation
// Programmer: Ken Brakke, brakke@susqu.edu, http://www.susqu.edu/brakke
// Usage: showequi
showequi := {
local ecount, al, nn, cl, dl, el, bl;
ecount := 0;
foreach edge ee do
{ al := ee.length;
nn := 1;
foreach ee.facet ff do
{ foreach ff.edge fe do
{ if ( fe.id != ee.id ) then
{ if ( nn == 1 ) then bl := fe.length
else if ( nn == 2 ) then cl := fe.length
else if ( nn == 3 ) then dl := fe.length
else if ( nn == 4 ) then el := fe.length;
nn := nn + 1;
}
}
};
if ( nn == 5 ) then
if (bl^2+cl^2-al^2)/bl/cl + (dl^2+el^2-al^2)/dl/el < -1e-5 then
{ set ee color green;
ecount := 1 + ecount
}
};
printf "Found %g edges.\n",ecount;
show_expr edges where 1
}
evolver-2.30c.dfsg/fe/slidestr.fe 0000644 0001753 0001753 00000003245 11410765113 017171 0 ustar hazelsct hazelsct // slidestr.fe
// Evolver data for drop of prescribed volume sitting
// on hyperbolic slide with gravity. Illustrates corner
// holding drop against gravity.
// Instructions for simple use:
// refine once
// iterate until drop settles into curve (datafile starts with
// gravity = 1 to pull drop down)
// Use `G' command to reverse gravity. Blob is stable up to
// about G = -.8
//
// You can color the blob edges with
// set edge color white where not fixed
STRING // one-dimensional surface
space_dimension 2
// Constraint of form m*x + x*y = k with m = 0.5, k = 0.1
// Integrals are used for volume, since zero density facets
// don't move, and their stretching around the curve gives
// an inaccurate volume.
PARAMETER STEEP = 0.5
PARAMETER SHARP = 0.1
constraint 1 // the slide, constants are steepness and sharpness
formula: STEEP*x + x*y = SHARP
content:
c1: log(x)*SHARP - STEEP*x // note this is indefinite integral of y
constraint 2 // the slide, for display
formula: STEEP*x + x*y = SHARP
vertices
1 0.0 2.2 constraint 1
2 0.0 0.8 constraint 1
3 0.5 2.2
4 0.5 0.8
5 0.0 2.5 constraint 2 fixed // for slide display
6 0.3 0.2 constraint 2 fixed // for slide display
7 1.5 .0 constraint 2 fixed // for slide display
edges /* given by endpoints and attribute */
1 2 4
2 4 3
3 3 1
4 5 6 fixed constraint 2 // for slide display
5 6 7 fixed constraint 2 // for slide display
faces /* given by oriented edge loop */
1 1 2 3
bodies /* one body, defined by its oriented faces */
1 1 volume 0.7 density 1.0
read
// Typical evolution, doing V's to keep vertices spread.
gogo := { r; {g 10; V;} 40 }
evolver-2.30c.dfsg/fe/jvx.cmd 0000755 0001753 0001753 00000020267 11410765113 016326 0 ustar hazelsct hazelsct // jvx.cmd
// Create jvx file for JavaView
// Usage: jvx >>> "filename.jvx"
// Programmer: Ken Brakke, brakke@susqu.edu, http://www.susqu.edu/brakke
define vertex attribute jvx_number integer; // for implicit vertex order
define facet attribute fjvxnum integer; // for implicit facet order
define facetcolorcount integer[16]; // to see which color facets are present
define edgecolorcount integer[16]; // to see which color edges are present
define rgb integer[16][3]; // color definitions
rgb[1][1] := 0; rgb[1][2] := 0; rgb[1][3] := 0;
rgb[2][1] := 0; rgb[2][2] := 0; rgb[2][3] := 255;
rgb[3][1] := 0; rgb[3][2] := 255; rgb[3][3] := 0;
rgb[4][1] := 0; rgb[4][2] := 255; rgb[4][3] := 255;
rgb[5][1] := 255; rgb[5][2] := 0; rgb[5][3] := 0;
rgb[6][1] := 255; rgb[6][2] := 0; rgb[6][3] := 255;
rgb[7][1] := 255; rgb[7][2] := 127; rgb[7][3] := 0;
rgb[8][1] := 160; rgb[8][2] := 160; rgb[8][3] := 160;
rgb[9][1] := 80; rgb[9][2] := 80; rgb[9][3] := 80;
rgb[10][1] := 80; rgb[10][2] := 200; rgb[10][3] := 255;
rgb[11][1] := 127; rgb[11][2] := 255; rgb[11][3] := 127;
rgb[12][1] := 127; rgb[12][2] := 255; rgb[12][3] := 255;
rgb[13][1] := 255; rgb[13][2] := 127; rgb[13][3] := 127;
rgb[14][1] := 255; rgb[13][2] := 127; rgb[13][3] := 255;
rgb[15][1] := 255; rgb[15][2] := 255; rgb[15][3] := 0;
rgb[16][1] := 255; rgb[16][2] := 255; rgb[16][3] := 255;
jvx := {
// First, bounding box.
maxx := max(vertex,x); minx := min(vertex,x);
maxy := max(vertex,y); miny := min(vertex,y);
maxz := max(vertex,z); minz := min(vertex,z);
printf "\n";
printf "\n";
printf "\n";
// printf "\n",date_and_time;
printf " %s \n",datafilename;
printf "1.0\n";
/*
printf "\n";
printf " \n";
printf " Kenneth\n";
printf " Brakke\n";
printf " \n";
printf " Susquehanna University\n";
printf " \n";
printf " Mathematics Department\n";
printf " Susquehanna University\n";
printf " Selinsgrove, PA 17870\n";
printf " USA\n";
printf " \n";
printf " \n";
printf " brakke@susqu.edu\n";
printf " http://www.susqu.edu/brakke\n";
printf " \n";
printf "\n";
printf "\n";
printf " One-line description of surface.\n";
printf " \n";
printf " Paragraph of description here.\n";
printf " \n";
printf " \n";
printf " minimal surface\n";
printf " \n";
printf " \n";
printf " 49Q20\n";
printf " optional \n";
printf " optional \n";
printf " \n";
printf " Surface Evolver 2.16\n";
printf "\n";
*/
printf "\n";
printf " \n";
printf " \n";
printf " \n",vertex_count;
jvxnum := 0;
foreach vertex vv do
{ printf " %f %f %f
\n",vv.x,vv.y,vv.z;
vv.jvx_number := jvxnum;
jvxnum += 1;
};
printf " \n";
printf " \n";
facetnum := 0;
foreach facet ff where ff.show and color != clear do
{ ff.fjvxnum := facetnum; facetnum += 1; };
colornum := 1;
while colornum <= 16 do { facetcolorcount[colornum] := 0; colornum += 1; };
foreach facet ff where ff.show and color != clear do
facetcolorcount[ff.color+1] += 1;
colornum := 1; numcolors := 0;
while colornum <= 16 do
{ if facetcolorcount[colornum] > 0 then numcolors += 1; colornum += 1; };
if numcolors > 1 then
printf " \n"
else printf " \n";
printf " \n",sum(facets,show);
foreach facet ff where ff.show and color != clear do
{ printf " %d %d %d \n",ff.vertex[1].jvx_number,
ff.vertex[2].jvx_number, ff.vertex[3].jvx_number;
};
if numcolors <= 1 then
{ colornum := 1;
while colornum <= 16 do
{ if facetcolorcount[colornum] > 0 then
printf " %d %d %d \n",rgb[colornum][1],
rgb[colornum][2],rgb[colornum][3];
colornum += 1;
};
};
printf " \n";
if numcolors > 1 then
{
printf " \n";
foreach facet ff where ff.show and color != clear do
{ printf " %d %d %d \n",rgb[ff.color+1][1],
rgb[ff.color+1][2],rgb[ff.color+1][3];
};
printf " \n";
};
printf " \n",sum(facets,show);
foreach facet ff where ff.show and color != clear do
printf " %d %d %d \n",
ff.edge[2].valence == 2 ?
max(ff.edge[2].facet where id != ff.id,fjvxnum) : -1,
ff.edge[3].valence == 2 ?
max(ff.edge[3].facet where id != ff.id,fjvxnum) : -1,
ff.edge[1].valence == 2 ?
max(ff.edge[1].facet where id != ff.id,fjvxnum) : -1;
printf " \n";
// printf " \n",sum(edges,show);
// foreach edge ee where ee.show do
// { printf " %d %d \n",ee.vertex[1].jvx_number,
// ee.vertex[2].jvx_number;
// };
// printf " 0 0 0 \n";
// printf " \n";
printf " \n";
printf " 1.0 \n";
printf " 0 0 0\n";
printf " \n";
printf " \n";
printf " \n";
printf " %f %f %f
\n",minx,miny,minz;
printf " %f %f %f
\n",maxx,maxy,maxz;
printf " \n";
printf " \n";
printf " %f %f %f
\n",(maxx+minx)/2,(maxy+miny)/2,
(maxz+minz)/2;
printf " \n";
printf " \n";
colornum := 1;
while colornum <= 16 do { edgecolorcount[colornum] := 0; colornum += 1; };
foreach edge ee where ee.show do
edgecolorcount[ee.color+1] += 1;
colornum := 1; numcolors := 0;
while colornum <= 16 do
{ if edgecolorcount[colornum] > 0 then numcolors += 1; colornum += 1; };
printf " \n";
printf " \n";
printf " \n",2*sum(edges,show);
foreach edge ee where ee.show do
{ printf " %f %f %f
\n",ee.vertex[1].x,ee.vertex[1].y,ee.vertex[1].z;
printf " %f %f %f
\n",ee.vertex[2].x,ee.vertex[2].y,ee.vertex[2].z;
};
printf " \n";
printf " \n";
if numcolors > 1 then
printf " \n"
else printf " \n";
printf " \n",sum(edges,show);
jvxnum := 0;
foreach edge ee where ee.show do
{ printf " %d %d \n",jvxnum,jvxnum+1;
jvxnum += 2;
};
printf " 2 \n";
if numcolors <= 1 then
{ colornum := 1;
while colornum <= 16 do
{ if edgecolorcount[colornum] > 0 then
printf " %d %d %d \n",rgb[colornum][1],
rgb[colornum][2],rgb[colornum][3];
colornum += 1;
};
};
printf " \n";
if ( numcolors > 1 ) then
{
printf " \n";
foreach edge ee where ee.show do
{ printf " %d %d %d \n", rgb[ee.color+1][1],
rgb[ee.color+1][2],rgb[ee.color+1][3];
};
printf " \n";
};
printf " \n";
printf " \n";
printf " %f %f %f
\n",minx,miny,minz;
printf " %f %f %f
\n",maxx,maxy,maxz;
printf " \n";
printf " \n";
printf " %f %f %f
\n",(maxx+minx)/2,(maxy+miny)/2,
(maxz+minz)/2;
printf " \n";
printf " \n";
printf "\n";
printf "\n";
}
evolver-2.30c.dfsg/fe/gzipdump.cmd 0000755 0001753 0001753 00000002041 11410765113 017344 0 ustar hazelsct hazelsct // gzipdump.cmd
// Evolver command for dumping datafile directly to gzip form
// Needs Evolver version 1.99e or later.
// Usage: gzipdump
// As is, this will dump to a gzipped file with a default name.
// You may change the filename in the command below to your own liking.
// gzipped file may be reloaded directly with shell command like
// /etc/mknod epipe p; ((gunzip epipe;rm epipe)& evolver epipe)
// I suggest defining a csh alias like
// alias gzev '/etc/mknod epipe p;((gzip -d < \!$ >epipe;rm epipe)& evolver \!:1- epipe)'
// so you can just do
// gzev cube.dmp.gz
// The alias even works with options, as in
// gzev -q -p2 cube.dmp.gz
dodump := {
list topinfo;
print "\nvertices\n"; list vertices;
print "\nedges\n"; list edges;
print "\nfaces\n"; list facets;
print "\nbodies\n"; list bodies;
list bottominfo
}
gzipdump := {
filename := sprintf "%s.dmp.gz",datafilename;
dumpcmd := sprintf "gzip >%s",filename;
printf "Dumping to %s\n",filename;
dodump | dumpcmd
}
evolver-2.30c.dfsg/fe/vrml.cmd 0000755 0001753 0001753 00000004771 11410765113 016501 0 ustar hazelsct hazelsct // vrml.cmd
// Makes VRML file for surface.
// Usage: Set edge_flag to 1 if you want do see all edges.
// Run "vrml" and re-direct output to file, e.g.
// Enter command: vrml >>> "myfile.wrl";
// Programmer: Ken Brakke, brakke@susqu.edu, http://www.susqu.edu/brakke
define vertex attribute order_num integer
edge_flag := 0 // 1 for all edges, 0 for special edges only
vrml := {
local counter;
counter := 0;
printf "#VRML V1.0 ascii\n\n";
printf "Separator {\n";
printf " DEF Title Info { string \"%s\" }\n",datafilename;
printf " DEF SceneInfo Info { string \"Created by Surface Evolver\" }\n";
printf " DEF BackgroundColor Info { string \".5 .6 1\" } \n";
printf " DirectionalLight { intensity .5 direction 0 0 -1 } \n";
printf " MaterialBinding { value PER_FACE_INDEXED }\n";
printf " Material { \n";
printf " diffuseColor [ 0.0 0.0 0.0 , 0.0 0.0 0.5 ,\n";
printf " 0.0 0.5 0.0 , 0.0 0.5 0.5 , 0.5 0.0 0.0 , 0.5 0.0 0.5 ,\n";
printf " 0.5 0.25 0. , .3 .3 .3 , .15 .15 .15 , .25 .25 .5 , .25 .5 .25 ,\n";
printf " .25 .5 .5 , .5 .25 .25 , .5 .25 .5 , .5 .5 .0 , .5 .5 .5 ] \n";
printf " emissiveColor [ 0.0 0.0 0.0 , 0.0 0.0 0.5 ,\n";
printf " 0.0 0.5 0.0 , 0.0 0.5 0.5 , 0.5 0.0 0.0 , 0.5 0.0 0.5 ,\n";
printf " 0.5 0.25 0. , .3 .3 .3 , .15 .15 .15 , .25 .25 .5 , .25 .5 .25 ,\n";
printf " .25 .5 .5 , .5 .25 .25 , .5 .25 .5 , .5 .5 .0 , .5 .5 .5 ] \n";
printf " }\n";
printf " Separator {\n";
printf " Coordinate3 { point [\n";
foreach vertex jvv do { printf " %f %f %f,\n",jvv.x,jvv.y,jvv.z;
set jvv order_num counter; counter := counter + 1; };
printf " ]\n }\n";
printf " IndexedFaceSet { coordIndex [\n";
foreach facet jff do printf " %g,%g,%g,-1,\n",
jff.vertex[1].order_num,jff.vertex[2].order_num,jff.vertex[3].order_num;
printf " ] \n";
printf " materialIndex [\n";
foreach facet jff do printf " %g,\n",jff.color;
printf " ]\n";
printf " }\n";
printf " Material { ambientColor 0 0 0 diffuseColor 0 0 0 }\n";
printf " IndexedLineSet { coordIndex [\n";
if edge_flag then
foreach edge jee do printf " %g,%g,-1,\n",
jee.vertex[1].order_num,jee.vertex[2].order_num
else foreach edge jee where valence != 2 do printf " %g,%g,-1,\n",
jee.vertex[1].order_num,jee.vertex[2].order_num;
printf " ] } \n";
printf " }\n";
printf "}\n";
} // end vrml
evolver-2.30c.dfsg/fe/phelanc.fe 0000644 0001753 0001753 00000017306 11410765113 016755 0 ustar hazelsct hazelsct // phelanc.fe
// Structure that beats Kelvin's partition of space.
// In 1887, Lord Kelvin posed the problem of finding the partition
// of space into equal volume cells minimizing the interface area.
// He suggested the cell shown in twointor.fe, which is basically
// the voronoi cell for a bcc lattice. Now Robert Phelan and Denis
// Weaire of Trinity College, Dublin, have found a structure using
// two types of cells that has 0.3% less area than Kelvin's. This is
// their Evolver datafile. There are 8 cells in a
// cubic 2x2x2 flat torus, which start as Voronoi cells on centers
//
// 0 0 0
// 1 1 1
// 0.5 0 1
// 1.5 0 1
// 0 1 0.5
// 0 1 1.5
// 1 0.5 0
// 1 1.5 0
// Just evolve to get the volumes all to 1, and Kelvin is beat.
// With more evolution, the ratio V^2/A^3 beats Kelvin by a
// whopping 1%. The Weaire-Phelan structure has its tetrakaidecahedra
// stacked on their hexagonal faces in three sets of perpendicular,
// mutually interlocking columns, with interstices filled by the
// dodecahedra.
// phelanc.fe with colored bodies
TORUS_FILLED
periods
2.000000 0.000000 0.000000
0.000000 2.000000 0.000000
0.000000 0.000000 2.000000
view_transform_generators 6
1 0 0 2
0 1 0 0
0 0 1 0
0 0 0 1
1 0 0 0
0 1 0 2
0 0 1 0
0 0 0 1
1 0 0 0
0 1 0 0
0 0 1 2
0 0 0 1
1 0 0 -2
0 1 0 0
0 0 1 0
0 0 0 1
1 0 0 0
0 1 0 -2
0 0 1 0
0 0 0 1
1 0 0 0
0 1 0 0
0 0 1 -2
0 0 0 1
vertices
1 1.374833 0.000542 0.313036
2 1.582639 1.583805 0.417091
3 1.999414 1.687884 0.625562
4 0.999778 0.000517 0.500564
5 1.686693 1.374893 1.999381
6 1.999036 0.312928 0.625224
7 0.416118 1.583554 0.417247
8 1.416641 1.417638 0.583002
9 0.999380 1.626008 0.687643
10 1.374528 0.000836 1.688167
11 1.582887 1.582882 1.583776
12 1.583228 0.416633 0.417188
13 0.415660 0.417170 0.416774
14 0.312152 1.375055 0.000199
15 1.999782 1.500468 1.000033
16 1.625132 1.312811 1.000465
17 1.312290 1.000953 0.374434
18 0.999015 1.625244 1.312907
19 0.582337 1.417418 0.583502
20 0.999205 0.000988 1.500509
21 1.582954 0.417290 1.583964
22 1.499589 1.000835 1.999244
23 1.687315 0.625137 1.999668
24 0.624322 0.000725 0.312769
25 0.416475 1.583942 1.583184
26 0.374830 1.313082 0.999521
27 1.624817 0.687664 1.000333
28 0.686621 1.000835 0.374834
29 1.416503 1.416444 1.417442
30 0.624634 0.000964 1.687531
31 1.999937 1.687755 1.375079
32 1.312386 1.000647 1.625031
33 0.499725 1.000658 0.000553
34 0.311830 0.624975 0.000488
35 0.375186 0.688291 0.999389
36 1.416715 0.583171 0.583818
37 0.582556 0.584101 0.583805
38 0.583642 1.417297 1.416440
39 1.999485 0.312616 1.375471
40 0.416489 0.416552 1.584015
41 1.999161 0.500331 0.999822
42 0.999925 0.375397 0.688204
43 0.688262 1.000529 1.624602
44 1.416155 0.584231 1.417123
45 0.584307 0.583998 1.416583
46 0.999499 0.376190 1.313024
edges
1 1 2 * - *
2 2 3 * * *
3 1 4 * * *
4 2 5 * * -
5 3 6 * + *
6 3 7 + * *
7 2 8 * * *
8 4 9 * - *
9 1 10 * * -
10 5 11 * * *
11 6 12 * * *
12 6 13 + * *
13 7 14 * * *
14 3 15 * * *
15 8 16 * * *
16 8 17 * * *
17 9 8 * * *
18 9 18 * * *
19 9 19 * * *
20 10 20 * * *
21 10 21 * * *
22 11 10 * + *
23 5 22 * * *
24 5 14 + * +
25 12 1 * * *
26 12 23 * * -
27 13 24 * * *
28 7 19 * * *
29 14 25 * * -
30 15 26 + * *
31 16 15 * * *
32 16 27 * * *
33 17 22 * * -
34 17 28 * * *
35 18 29 * * *
36 19 26 * * *
37 20 30 * * *
38 21 23 * * *
39 11 31 * * *
40 11 29 * * *
41 22 32 * * *
42 14 33 * * *
43 23 34 + * +
44 24 7 * - *
45 24 30 * * -
46 19 28 * * *
47 25 30 * + *
48 25 31 - * *
49 26 35 * * *
50 16 29 * * *
51 27 36 * * *
52 17 36 * * *
53 28 33 * * *
54 28 37 * * *
55 18 38 * * *
56 29 32 * * *
57 26 38 * * *
58 20 18 * - *
59 31 39 * + *
60 22 23 * * *
61 33 34 * * *
62 34 13 * * *
63 34 40 * * -
64 30 40 * * *
65 35 41 - * *
66 35 37 * * *
67 36 12 * * *
68 36 42 * * *
69 33 43 * * -
70 37 42 * * *
71 37 13 * * *
72 38 25 * * *
73 32 43 * * *
74 32 44 * * *
75 24 4 * * *
76 35 45 * * *
77 21 39 * * *
78 39 40 + * *
79 41 27 * * *
80 42 46 * * *
81 43 38 * * *
82 42 4 * * *
83 44 27 * * *
84 44 46 * * *
85 15 31 * * *
86 45 43 * * *
87 45 46 * * *
88 41 39 * * *
89 21 44 * * *
90 6 41 * * *
91 46 20 * * *
92 45 40 * * *
faces
1 1 2 5 11 25 color 1 backcolor 4
2 -1 3 8 17 -7 color 8 backcolor 4
3 2 6 13 -24 -4 color 5 backcolor 1
4 5 12 27 44 -6 color 3 backcolor 1
5 11 26 43 62 -12 color 5 backcolor 1
6 1 4 10 22 -9 color 8 backcolor 1
7 17 16 34 -46 -19 color 2 backcolor 8
8 7 16 33 -23 -4 color 8 backcolor 5
9 -2 7 15 31 -14 color 5 backcolor 4
10 -6 14 30 -36 -28 color 5 backcolor 3
11 -13 28 46 53 -42 color 5 backcolor 8
12 24 29 48 -39 -10 color 6 backcolor 1
13 44 13 29 47 -45 color 1 backcolor 8
14 62 27 45 64 -63 color 1 backcolor 7
15 25 9 21 38 -26 color 7 backcolor 1
16 -3 9 20 37 -45 75 color 8 backcolor 7
17 -10 23 41 -56 -40 color 8 backcolor 6
18 -22 39 59 -77 -21 color 4 backcolor 1
19 8 19 -28 -44 75 color 3 backcolor 8
20 -18 19 36 57 -55 color 2 backcolor 3
21 -17 18 35 -50 -15 color 2 backcolor 4
22 34 53 69 -73 -41 -33 color 8 backcolor 7
23 -46 36 49 66 -54 color 5 backcolor 2
24 -16 15 32 51 -52 color 2 backcolor 5
25 31 30 49 65 79 -32 color 6 backcolor 5
26 -53 54 71 -62 -61 color 5 backcolor 7
27 42 61 -43 -60 -23 24 color 5 backcolor 6
28 48 59 78 -64 -47 color 1 backcolor 3
29 43 63 -78 -77 38 color 1 backcolor 6
30 -41 60 -38 89 -74 color 7 backcolor 6
31 -56 -35 55 -81 -73 color 2 backcolor 8
32 40 -35 -58 -20 -22 color 8 backcolor 4
33 -57 -30 85 -48 -72 color 6 backcolor 3
34 50 56 74 83 -32 color 2 backcolor 6
35 34 54 70 -68 -52 color 7 backcolor 2
36 69 81 72 -29 42 color 6 backcolor 8
37 -33 52 67 26 -60 color 7 backcolor 5
38 49 76 86 81 -57 color 2 backcolor 6
39 66 71 -12 90 -65 color 3 backcolor 5
40 51 67 -11 90 79 color 5 backcolor 4
41 -37 58 55 72 47 color 8 backcolor 3
42 -89 -21 20 -91 -84 color 7 backcolor 4
43 74 84 -87 86 -73 color 7 backcolor 2
44 83 51 68 80 -84 color 4 backcolor 2
45 70 82 -75 -27 -71 color 3 backcolor 7
46 -68 67 25 3 -82 color 4 backcolor 7
47 -69 61 63 -92 86 color 6 backcolor 7
48 -76 65 88 78 -92 color 3 backcolor 6
49 -66 76 87 -80 -70 color 3 backcolor 2
50 90 88 -59 -85 -14 5 color 4 backcolor 3
51 79 -83 -89 77 -88 color 4 backcolor 6
52 -91 -87 92 -64 -37 color 3 backcolor 7
53 -85 -31 50 -40 39 color 6 backcolor 4
54 -82 80 91 58 -18 -8 color 3 backcolor 4
bodies
1 1 -3 -4 -5 -6 -12 13 14 -15 -18 28 29 volume 0.976527
2 7 20 21 -23 24 31 34 -35 38 -43 -44 -49 volume 0.976538
3 39 45 48 49 -50 4 54 -28 52 -33 19 -20 -41 -10 volume 1.007698
4 -40 44 46 50 51 -1 -42 -54 -53 -9 18 -2 -32 -21 volume 1.007902
5 3 -8 9 10 11 -24 -25 23 26 27 -37 40 -39 5 volume 1.007528
6 33 -38 25 12 36 -48 53 -51 -34 -27 47 -17 -30 -29 volume 1.008217
7 -22 30 35 -26 37 42 43 -45 -46 -47 15 -52 -16 -14 volume 1.008071
8 2 6 -7 8 16 17 -19 22 -31 32 -36 -11 41 -13 volume 1.007564
read
set body target 1
column_color := { /* colors bodies alike that are in same columns */
set facet frontcolor green where frontcolor==blue;
set facet backcolor green where backcolor==blue;
set facet frontcolor red where frontcolor==cyan;
set facet backcolor red where backcolor==cyan;
set facet frontcolor lightgray where frontcolor==darkgray;
set facet backcolor lightgray where backcolor==darkgray;
set facet frontcolor magenta where frontcolor==brown;
set facet backcolor magenta where backcolor==brown;
}
dodecs:= show facet ff where max(ff.body,id==1 or id==2)
column1:= show facet ff where max(ff.body,id==3 or id==4)
column2:= show facet ff where max(ff.body,id==5 or id==6)
column3:= show facet ff where max(ff.body,id==7 or id==8)
bunch := transform_expr "abc"
lots := transform_expr "abcdef"
few := transforms off
all := show facet
// Typical evolution
gogo := { g 5; r; g 5; hessian; r; g 5; hessian; }
evolver-2.30c.dfsg/fe/iges136.cmd 0000755 0001753 0001753 00000014766 11410765113 016707 0 ustar hazelsct hazelsct // iges136.cmd
// Surface Evolver script to write IGES file for surface, using IGES
// finite element entity (type 136), which handles linear, quadratic,
// and cubic triangles (among many other types not of interest).
// Finite element type not official "geometry"???? Rhino says can't
// find any independent geometry, and http://www.iges5x.org/taxonomy/ has
// FEM types included under "non-geometry taxonomy'.
// Also not listed in Table 3 on p. 38 of IGES-6 documentation.
// Programmer: Ken Brakke, brakke@susqu.edu, http://www.susqu.edu/brakke
// usage: iges >>> "filename.igs"
iges := {
// Flag section
// Don't need this since not doing binary or compressed format.
// Start section
start_counter := 0;
start_counter += 1;
printf "%-72sS%07d\n","IGES version of Surface Evolver surface",start_counter;
start_counter += 1;
printf " %-69sS%07d\n",datafilename,start_counter;
start_counter += 1;
printf "%-72sS%07d\n","Created using iges.cmd Evolver script.",
start_counter;
// Global section
global_counter := 0;
global_counter += 1;
printf "%-72sG%07d\n","1H,,1H;,",global_counter;
global_counter += 1;
printf "%02dH%-69sG%07d\n",sizeof("Surface Evolver"),"Surface Evolver,",
global_counter;
global_counter += 1;
message := sprintf "%s,",datafilename;
printf "%02dH%-69sG%07d\n",sizeof(datafilename),message,global_counter;
global_counter += 1;
printf "%02dH%-69sG%07d\n",sizeof("Surface Evolver"),"Surface Evolver,",
global_counter;
global_counter += 1;
printf "%02dH%-69sG%07d\n",sizeof("Surface Evolver"),"Surface Evolver,",
global_counter;
global_counter += 1;
printf "%-72sG%07d\n","32,75,6,75,15,,1.0,1,2HIN,32768,0.0394,",
global_counter;
global_counter += 1;
printf "%-72sG%07d\n","15H00000000.000000,", global_counter; // date
xmax := max(vertex,abs(x));
ymax := max(vertex,abs(y));
zmax := max(vertex,abs(z));
maxsize := (xmax > ymax) ? xmax : ymax;
maxsize := (zmax > maxsize) ? zmax : maxsize;
message := sprintf "%g,%g,",maxsize/10000000,maxsize;
global_counter += 1;
printf "%-72sG%07d\n",message, global_counter;
global_counter += 1;
printf "%02dH%-69sG%07d\n",sizeof("Name of author"),"Name of author,",
global_counter;
global_counter += 1;
printf "%02dH%-69sG%07d\n",sizeof("Author's organization"),
"Author's organization,", global_counter;
global_counter += 1;
printf "%-72sG%07d\n","15H00000000.000000;", global_counter; // date
// Directory entry section. Each entry 20 8-char fields on two lines.
// Fields with default values
entype := 0; // 1 and 11
paramdata := 0; // 2
structure := 0; // 3
linefont := 0; // 4
level := 0; // 5
view := 0; // 6
transmat := 0; // 7
label := 0; // 8
status := "00000000"; // 9; actually 4 two-digit numbers
directory_counter := 0; // 10 and 20
lineweight := 0; // 12
colornum := 0; // 13
paramcount := 0; // 14
form := 0; // 15
reserved := " "; // 16 and 17
entlabel := "entity"; // 18
entsubscr := 0; // 19
// Vertices as "node" types
entype := 135;
status := "00010401";
paramcount := 1;
entlabel := " VERTEX";
define vertex attribute pdata integer;
define vertex attribute dir integer;
foreach vertex vv do
{ paramdata += 1; vv.pdata := paramdata;
entsubscr := vv.id;
directory_counter += 1; vv.dir := directory_counter;
printf "%8d%8d%8d%8d%8d%8d%8d%8d%8sD%7d\n",entype,paramdata,structure,
linefont,level,view,transmat,label,status,directory_counter;
directory_counter += 1;
printf "%8d%8d%8d%8d%8d%8s%8s%8s%8dD%7d\n",entype,lineweight,colornum,
paramcount,form,reserved,reserved,entlabel,entsubscr,directory_counter;
};
// Facets as "finite element" types
entype := 136;
status := "00010001";
paramcount := 1;
entlabel := " FACET";
define facet attribute fpdata integer;
define facet attribute fdir integer;
foreach facet ff do
{ paramdata += 1; ff.fpdata := paramdata;
entsubscr := ff.id;
directory_counter += 1; ff.fdir := directory_counter;
printf "%8d%8d%8d%8d%8d%8d%8d%8d%8sD%7d\n",entype,paramdata,structure,
linefont,level,view,transmat,label,status,directory_counter;
directory_counter += 1;
printf "%8d%8d%8d%8d%8d%8s%8s%8s%8dD%7d\n",entype,lineweight,colornum,
paramcount,form,reserved,reserved,entlabel,entsubscr,directory_counter;
};
// Geometry element
entype := 402;
status := "00000301";
paramcount := ceil(facet_count/10);
form := 7;
entlabel := " SURFACE";
paramdata += 1;
entsubscr := 1;
directory_counter += 1;
printf "%8d%8d%8d%8d%8d%8d%8d%8d%8sD%7d\n",entype,paramdata,structure,
linefont,level,view,transmat,label,status,directory_counter;
directory_counter += 1;
printf "%8d%8d%8d%8d%8d%8s%8s%8s%8dD%7d\n",entype,lineweight,colornum,
paramcount,form,reserved,reserved,entlabel,entsubscr,directory_counter;
// Parameter data section
parameter_counter := 0;
// Vertices
entype := 134;
foreach vertex vv do
{ parameter_counter += 1;
if vv.pdata != parameter_counter then
errprintf
"ERROR: bad vertex parameter line number, vertex %d. Is %d, should be %d.\n",
vv.id,parameter_counter,vv.pdata;
message := sprintf "%d,%13.10f,%13.10f,%13.10f,0;",entype,vv.x,vv.y,vv.z;
printf "%-64s%8dP%7d\n",message,vv.dir,parameter_counter;
};
// Facets
entype := 136;
itop := 2; // Linear TRIAngle
etyp := "5HLTRIA";
numnodes := 3;
foreach facet ff do
{ parameter_counter += 1;
if ff.fpdata != parameter_counter then
errprintf
"ERROR: bad facet parameter line number, facet %d. Is %d, should be %d.\n",
ff.id,parameter_counter,ff.fpdata;
message := sprintf "%d,%d,%d,%d,%d,%d,%s;",entype,itop,numnodes,
ff.vertex[1].dir,ff.vertex[2].dir,ff.vertex[3].dir,etyp;
printf "%-64s%8dP%7d\n",message,ff.fdir,parameter_counter;
};
// Geometry element
line := sprintf "402,%d,",facet_count;
subcount := 0;
foreach facet ff do
{ if subcount == 10 then
{
parameter_counter += 1;
printf "%-64s%8dP%7d\n",line,directory_counter-1,parameter_counter;
line := "" ;
};
line := sprintf"%s%d,",line,ff.fdir;
};
line := sprintf "%s0,0;",line; // sample files ended with 2 extra 0's
parameter_counter += 1;
printf "%-64s%8dP%7d\n",line,directory_counter-1,parameter_counter;
// Terminate section
printf "S%07dG%07dD%07dP%07d%40sT0000001\n",start_counter,global_counter,
directory_counter,parameter_counter," ";
}
evolver-2.30c.dfsg/fe/wavefront.cmd 0000755 0001753 0001753 00000003000 11410765113 017514 0 ustar hazelsct hazelsct // wavefront.cmd
// Surface Evolver command file for producing Wavefront format file
// for surface, suitable for feeding to JavaView.
// Programmer: Ken Brakke, brakke@susqu.edu, http://www.susqu.edu/brakke
// Usage:
// wavefront >>> "filename.obj"
// or, for version with normals at vertices,
// wavefrontn >>> "filename.obj"
define vertex attribute v_num integer
wavefront := {
// Make sure vertices consecutively numbered
new_v_num := 1;
foreach vertex vv do { vv.v_num := new_v_num; new_v_num += 1 };
printf "# Wavefront .obj file for %s\n",datafilename;
printf "# Produced by the Surface Evolver.\n\n";
foreach vertex vv do printf "v %f %f %f\n",vv.x,vv.y,vv.z;
printf "\n";
foreach facet ff do printf "f %g %g %g\n",ff.vertex[1].v_num,
ff.vertex[2].v_num, ff.vertex[3].v_num;
}
// version with normals at vertices
wavefrontn := {
// Make sure vertices consecutively numbered
new_v_num := 1;
foreach vertex vv do { vv.v_num := new_v_num; new_v_num += 1 };
printf "# Wavefront .obj file for %s\n",datafilename;
printf "# Produced by the Surface Evolver.\n\n";
foreach vertex vv do printf "v %f %f %f\n",vv.x,vv.y,vv.z;
printf "\n";
foreach vertex vv do printf "vn %f %f %f\n",vv.vertexnormal[1],
vv.vertexnormal[2],vv.vertexnormal[3];
printf "\n";
foreach facet ff do printf "f %g/%g %g/%g %g/%g\n",ff.vertex[1].v_num,
ff.vertex[1].v_num, ff.vertex[2].v_num,
ff.vertex[2].v_num, ff.vertex[3].v_num,
ff.vertex[3].v_num;
}
evolver-2.30c.dfsg/fe/polyfilm.cmd 0000755 0001753 0001753 00000002225 11410765113 017344 0 ustar hazelsct hazelsct // polyfilm.cmd
// command to produce Polycut format file
// usage: polyfilm >>> "filename"
// Programmer: Ken Brakke, brakke@susqu.edu, http://www.susqu.edu/brakke
define vertex attribute offnumber integer;
// command to print OFF format part (the vertices and facets)
verlist := { local offnum;
offnum := 0;
foreach vertex vv do
{ printf "%f %f %f \n",x,y,z;
vv.offnumber := offnum;
offnum += 1;
}
} // end verlist
facelist := { foreach facet ff do
{ printf "3 ";
foreach ff.vertex vv do printf "%g ",vv.offnumber;
printf "\n";
}
} // end facelist
do_off := { printf "OFF\n%g %g %g\n",vertex_count,facet_count,edge_count;
verlist;
facelist
} // end do_off
// vect-like file command for triple lines
traa := { trcount ::= sum(edges where valence==3,1)}
trbb := { foreach edge ee where ee.valence==3 do
{ foreach ee.vertex vv do printf "%f %f %f ",x,y,z ;
printf "\n";
}
}
trips := { printf "TRIPLE\n"; traa; printf "%g\n",trcount; trbb }
polyfilm := {do_off; trips}
evolver-2.30c.dfsg/fe/100grain.fe 0000644 0001753 0001753 00000035154 11410765113 016665 0 ustar hazelsct hazelsct // 2D Voronoi diagram of 100 cells in unit torus.
// With automatic popping and chopping.
// Usage: just load in Evolver and do 'g' steps. You can do them
// in big chunks, say 10000 at a time.
STRING
SPACE_DIMENSION 2
TORUS
PERIODS
1.0 0.0
0.0 1.0
autopop
autochop 0.015000
area_normalization
scale 5e-006 fixed
VERTICES
1 -0.030008 0.140444
2 -0.053561 0.142482
3 -0.053946 0.142913
4 -0.043174 0.262670
5 -0.030826 0.272623
6 -0.002732 0.263058
7 0.030515 0.186263
8 0.229526 0.892844
9 0.197250 0.830725
10 0.164128 0.845516
11 0.155140 0.891287
12 0.175151 0.917947
13 0.013457 0.904425
14 0.019242 0.903750
15 0.099088 0.822584
16 0.099238 0.797112
17 0.038472 0.769136
18 0.345511 0.867172
19 0.316990 0.895976
20 0.302884 0.933134
21 0.305616 0.970797
22 0.502700 0.988511
23 0.513272 0.938981
24 0.467254 0.873503
25 0.358794 0.760227
26 0.421715 0.745342
27 0.447609 0.623441
28 0.386207 0.547841
29 0.379759 0.543637
30 0.327500 0.540091
31 0.301920 0.560712
32 0.038356 0.911818
33 0.074852 0.917690
34 0.109014 0.031672
35 0.082139 0.059863
36 0.116979 0.117814
37 0.169077 0.147739
38 0.249566 0.102936
39 0.265711 0.083110
40 0.263516 0.061681
41 0.157972 0.022724
42 0.668828 0.702216
43 0.657217 0.709184
44 0.648690 0.726695
45 0.639862 0.849299
46 0.671332 0.879221
47 0.795602 0.874217
48 0.825169 0.863559
49 0.822140 0.854479
50 0.051843 0.463089
51 -0.008885 0.547199
52 -0.009018 0.554344
53 0.064609 0.593106
54 0.195952 0.584518
55 0.715969 0.035473
56 0.720991 0.077810
57 0.759825 0.154628
58 0.803906 0.131127
59 0.832758 0.097005
60 0.840144 0.056532
61 0.828317 0.038418
62 0.793569 0.016632
63 0.866798 0.634036
64 0.874315 0.608119
65 0.810168 0.563294
66 0.722718 0.611416
67 0.686430 0.661210
68 0.674258 0.697043
69 0.736065 0.704853
70 0.799285 0.697204
71 0.128274 0.421961
72 0.151241 0.424619
73 0.270736 0.385808
74 0.252679 0.348670
75 0.163426 0.278401
76 0.120465 0.335411
77 0.923424 0.139123
78 0.957650 0.073212
79 0.935431 0.025421
80 0.671668 0.089803
81 0.620645 0.141321
82 0.653768 0.179083
83 0.714382 0.195884
84 0.749149 0.170561
85 0.897672 0.454661
86 0.900534 0.482589
87 1.053106 0.457102
88 1.015103 0.398474
89 0.966433 0.356965
90 0.960711 0.360602
91 0.913244 0.405778
92 0.153045 0.773386
93 0.209507 0.805331
94 0.238979 0.775913
95 0.165918 0.722482
96 0.102759 1.006934
97 0.147549 0.957675
98 0.132490 0.954404
99 0.034313 0.180479
100 0.029867 0.134185
101 0.025138 0.128845
102 0.432624 0.437038
103 0.434238 0.453639
104 0.529974 0.419934
105 0.533843 0.416214
106 0.542179 0.349833
107 0.493588 0.324922
108 0.020543 0.263635
109 0.087614 0.335281
110 0.593847 0.456960
111 0.654644 0.445022
112 0.648907 0.417561
113 0.615874 0.343447
114 0.589189 0.330605
115 1.035042 0.079044
116 0.836275 0.779507
117 0.870909 0.890102
118 0.879339 0.892276
119 0.945582 0.887996
120 0.943789 0.834657
121 0.906471 0.738313
122 0.904679 0.737826
123 0.471347 0.306478
124 0.393143 0.335959
125 0.833147 0.245908
126 0.830435 0.241033
127 0.716296 0.231275
128 0.730788 0.289488
129 0.734095 0.289792
130 0.770476 0.418024
131 0.763693 0.431898
132 0.818061 0.530796
133 0.106657 0.781975
134 0.203174 0.820975
135 0.075784 0.139866
136 0.068339 0.176548
137 0.305266 0.880414
138 0.354191 0.763363
139 0.265994 0.753654
140 0.246446 0.772642
141 0.159245 0.265211
142 0.138670 0.234806
143 0.861916 0.186777
144 0.174082 0.940799
145 0.279948 1.009278
146 0.273393 0.288033
147 0.271448 0.386266
148 0.370404 0.332813
149 0.361161 0.275986
150 0.323080 0.261652
151 0.829893 0.311422
152 0.858517 0.273344
153 0.588934 0.250300
154 0.520092 0.070927
155 0.454613 0.150364
156 0.470693 0.190299
157 0.271767 0.226323
158 0.265901 0.219436
159 0.556483 0.563129
160 0.546308 0.638700
161 0.631007 0.553525
162 0.821470 0.375664
163 0.770607 0.417231
164 0.758282 0.954513
165 0.780616 0.971172
166 0.977825 0.939932
167 0.979590 0.912835
168 0.138699 0.234511
169 0.235663 0.594778
170 0.592619 0.309939
171 0.398289 0.170783
172 0.409605 0.154346
173 0.311022 0.227565
174 0.672435 0.458037
175 0.695586 0.463138
176 0.728091 0.343070
177 0.145115 0.682641
178 0.099338 0.699126
179 0.719575 0.318548
180 0.058977 0.057878
181 0.895069 0.729562
182 0.624958 0.535856
183 0.575125 0.513126
184 0.554961 0.523143
185 0.524879 0.511588
186 0.522569 0.050489
187 0.977322 0.677757
188 0.964115 0.598347
189 0.695639 0.943549
190 0.082714 0.694723
191 0.218466 0.595225
192 0.206052 0.587706
193 0.832707 0.335253
194 0.021993 0.747569
195 0.937054 0.260196
196 0.867310 0.188595
197 0.680799 1.007336
198 0.656663 0.017536
199 0.461951 0.779741
200 1.023159 0.705505
EDGES
1 1 2 * *
2 2 3 * *
3 3 4 * *
4 4 5 * *
5 5 6 * *
6 6 7 * *
7 7 1 * *
8 8 9 * *
9 9 10 * *
10 10 11 * *
11 11 12 * *
12 12 8 * *
13 13 14 * *
14 14 15 * *
15 15 16 * *
16 16 17 * *
17 17 13 * *
18 18 19 * *
19 19 20 * *
20 20 21 * *
21 21 22 * *
22 22 23 * *
23 23 24 * *
24 24 18 * *
25 25 26 * *
26 26 27 * *
27 27 28 * *
28 28 29 * *
29 29 30 * *
30 30 31 * *
31 31 25 * *
32 10 15 * *
33 14 32 * *
34 32 33 * *
35 33 11 * *
36 34 35 * *
37 35 36 * *
38 36 37 * *
39 37 38 * *
40 38 39 * *
41 39 40 * *
42 40 41 * *
43 41 34 * *
44 42 43 * *
45 43 44 * *
46 44 45 * *
47 45 46 * *
48 46 47 * *
49 47 48 * *
50 48 49 * *
51 49 42 * *
52 50 51 * *
53 51 52 * *
54 52 53 * *
55 53 54 * *
56 54 50 * *
57 55 56 * *
58 56 57 * *
59 57 58 * *
60 58 59 * *
61 59 60 * *
62 60 61 * *
63 61 62 * *
64 62 55 * *
65 63 64 * *
66 64 65 * *
67 65 66 * *
68 66 67 * *
69 67 68 * *
70 68 69 * *
71 69 70 * *
72 70 63 * *
73 71 72 * *
74 72 73 * *
75 73 74 * *
76 74 75 * *
77 75 76 * *
78 76 71 * *
79 77 3 + *
80 2 78 - *
81 78 79 * *
82 79 60 * *
83 59 77 * *
84 80 81 * *
85 81 82 * *
86 82 83 * *
87 83 84 * *
88 84 57 * *
89 56 80 * *
90 85 86 * *
91 86 51 + *
92 50 87 - *
93 87 88 * *
94 88 89 * *
95 89 90 * *
96 90 91 * *
97 91 85 * *
98 92 93 * *
99 93 94 * *
100 94 95 * *
101 95 92 * *
102 96 34 * +
103 41 97 * -
104 97 98 * *
105 98 96 * *
106 7 99 * *
107 99 100 * *
108 100 101 * *
109 101 1 * *
110 102 103 * *
111 103 104 * *
112 104 105 * *
113 105 106 * *
114 106 107 * *
115 107 102 * *
116 108 6 * *
117 5 89 - *
118 88 109 + *
119 109 108 * *
120 110 111 * *
121 111 112 * *
122 112 113 * *
123 113 114 * *
124 114 106 * *
125 105 110 * *
126 101 115 - *
127 115 78 * *
128 116 49 * *
129 48 117 * *
130 117 118 * *
131 118 119 * *
132 119 120 * *
133 120 121 * *
134 121 122 * *
135 122 116 * *
136 107 123 * *
137 123 124 * *
138 124 102 * *
139 68 42 * *
140 116 69 * *
141 125 126 * *
142 126 84 * *
143 83 127 * *
144 127 128 * *
145 128 129 * *
146 129 125 * *
147 130 131 * *
148 131 132 * *
149 132 86 * *
150 85 130 * *
151 92 133 * *
152 133 16 * *
153 9 134 * *
154 134 93 * *
155 135 100 * *
156 99 136 * *
157 136 135 * *
158 137 19 * *
159 18 138 * *
160 138 139 * *
161 139 140 * *
162 140 137 * *
163 87 71 + *
164 76 109 * *
165 75 141 * *
166 141 142 * *
167 142 108 * *
168 143 58 * *
169 126 143 * *
170 33 98 * *
171 97 144 * *
172 144 12 * *
173 40 145 * -
174 145 144 * *
175 146 74 * *
176 73 147 * *
177 147 148 * *
178 148 149 * *
179 149 150 * *
180 150 146 * *
181 8 20 * *
182 137 134 * *
183 129 151 * *
184 151 152 * *
185 152 125 * *
186 153 82 * *
187 81 154 * *
188 154 155 * *
189 155 156 * *
190 156 153 * *
191 146 157 * *
192 157 158 * *
193 158 141 * *
194 159 160 * *
195 160 43 * *
196 67 161 * *
197 161 159 * *
198 91 162 * *
199 162 163 * *
200 163 130 * *
201 164 165 * *
202 165 117 * *
203 47 164 * *
204 79 166 * -
205 166 167 * *
206 167 119 * *
207 118 61 * +
208 136 168 * *
209 168 37 * *
210 36 135 * *
211 31 169 * *
212 169 139 * *
213 138 25 * *
214 153 170 * *
215 170 127 * *
216 171 172 * *
217 172 39 * *
218 38 158 * *
219 157 173 * *
220 173 171 * *
221 111 174 * *
222 174 175 * *
223 175 131 * *
224 163 176 * *
225 176 112 * *
226 95 177 * *
227 177 178 * *
228 178 133 * *
229 170 114 * *
230 113 179 * *
231 179 128 * *
232 145 21 * *
233 13 167 - *
234 166 180 + +
235 180 35 * *
236 96 32 * *
237 70 181 * *
238 181 63 * *
239 161 182 * *
240 182 183 * *
241 183 184 * *
242 184 159 * *
243 185 184 * *
244 183 110 * *
245 104 185 * *
246 66 175 * *
247 174 182 * *
248 140 94 * *
249 180 115 - *
250 172 155 * *
251 154 186 * *
252 186 22 * -
253 181 122 * *
254 121 187 * *
255 187 188 * *
256 188 64 * *
257 150 173 * *
258 149 171 * *
259 46 189 * *
260 189 164 * *
261 156 123 * *
262 190 178 * *
263 177 191 * *
264 191 192 * *
265 192 54 * *
266 53 190 * *
267 169 191 * *
268 179 176 * *
269 162 193 * *
270 193 151 * *
271 17 194 * *
272 194 120 - *
273 165 62 * +
274 103 29 * *
275 28 185 * *
276 152 195 * *
277 195 196 * *
278 196 143 * *
279 189 197 * *
280 197 55 * +
281 124 148 * *
282 147 30 * *
283 198 186 * *
284 80 198 * *
285 24 199 * *
286 199 26 * *
287 160 27 * *
288 199 44 * *
289 45 23 * *
290 198 197 * -
291 4 195 - *
292 193 90 * *
293 192 72 * *
294 65 132 * *
295 52 188 - *
296 187 200 * *
297 200 190 + *
298 142 168 * *
299 200 194 + *
300 196 77 * *
FACES
1 -7 -6 -5 -4 -3 -2 -1
2 -12 -11 -10 -9 -8
3 -17 -16 -15 -14 -13
4 -24 -23 -22 -21 -20 -19 -18
5 -31 -30 -29 -28 -27 -26 -25
6 -35 -34 -33 14 -32 10
7 -43 -42 -41 -40 -39 -38 -37 -36
8 -51 -50 -49 -48 -47 -46 -45 -44
9 -56 -55 -54 -53 -52
10 -64 -63 -62 -61 -60 -59 -58 -57
11 -72 -71 -70 -69 -68 -67 -66 -65
12 -78 -77 -76 -75 -74 -73
13 -83 61 -82 -81 -80 2 -79
14 -89 58 -88 -87 -86 -85 -84
15 -97 -96 -95 -94 -93 -92 52 -91 -90
16 -101 -100 -99 -98
17 -105 -104 -103 43 -102
18 7 -109 -108 -107 -106
19 -115 -114 -113 -112 -111 -110
20 -119 -118 94 -117 5 -116
21 -125 113 -124 -123 -122 -121 -120
22 -127 -126 109 1 80
23 -135 -134 -133 -132 -131 -130 -129 50 -128
24 115 -138 -137 -136
25 -140 128 51 -139 70
26 -146 -145 -144 -143 87 -142 -141
27 -150 90 -149 -148 -147
28 98 -154 -153 9 32 15 -152 -151
29 -157 -156 107 -155
30 -162 -161 -160 -159 18 -158
31 118 -164 78 -163 93
32 119 -167 -166 -165 77 164
33 -169 142 88 59 -168
34 35 11 -172 -171 104 -170
35 103 171 -174 -173 42
36 -180 -179 -178 -177 -176 75 -175
37 -182 158 19 -181 8 153
38 146 -185 -184 -183
39 -190 -189 -188 -187 85 -186
40 -193 -192 -191 175 76 165
41 -197 -196 69 139 44 -195 -194
42 150 -200 -199 -198 97
43 -203 49 129 -202 -201
44 -207 131 -206 -205 -204 82 62
45 157 -210 38 -209 -208
46 31 -213 160 -212 -211
47 -215 -214 186 86 143
48 -220 -219 192 -218 40 -217 -216
49 -225 -224 200 147 -223 -222 -221 121
50 101 151 -228 -227 -226
51 215 144 -231 -230 123 -229
52 12 181 20 -232 174 172
53 -236 102 36 -235 -234 205 -233 13 33
54 -238 -237 72
55 197 -242 -241 -240 -239
56 -245 112 125 -244 241 -243
57 -247 222 -246 68 196 239
58 182 154 99 -248 162
59 155 108 126 -249 235 37 210
60 21 -252 -251 188 -250 217 41 173 232
61 238 65 -256 -255 -254 134 -253
62 -257 180 191 219
63 257 220 -258 179
64 203 -260 -259 48
65 190 214 229 124 114 136 -261
66 -266 55 -265 -264 -263 227 -262
67 100 226 263 -267 212 161 248
68 183 -270 -269 199 224 -268 231 145
69 105 236 34 170
70 127 81 204 234 249
71 17 233 206 132 -272 -271
72 202 130 207 63 -273
73 245 -275 28 -274 111
74 169 -278 -277 -276 185 141
75 140 71 237 253 135
76 201 273 64 -280 -279 260
77 225 122 230 268
78 138 110 274 29 -282 177 -281
79 -284 84 187 251 -283
80 24 159 213 25 -286 -285
81 -288 286 26 -287 195 45
82 279 -290 283 252 22 -289 47 259
83 -292 270 184 276 -291 4 117 95
84 -293 265 56 92 163 73
85 284 290 280 57 89
86 247 240 244 120 221
87 246 223 148 -294 67
88 242 194 287 27 275 243
89 292 96 198 269
90 266 -297 -296 255 -295 54
91 156 208 -298 167 116 6 106
92 16 271 -299 297 262 228 152
93 -300 278 168 60 83
94 293 74 176 282 30 211 267 264
95 300 79 3 291 277
96 193 166 298 209 39 218
97 272 133 254 296 299
98 149 91 53 295 256 66 294
99 288 46 289 23 285
100 258 216 250 189 261 137 281 178
BODIES
1 1
2 2
3 3
4 4
5 5
6 6
7 7
8 8
9 9
10 10
11 11
12 12
13 13
14 14
15 15
16 16
17 17
18 18
19 19
20 20
21 21
22 22
23 23
24 24
25 25
26 26
27 27
28 28
29 29
30 30
31 31
32 32
33 33
34 34
35 35
36 36
37 37
38 38
39 39
40 40
41 41
42 42
43 43
44 44
45 45
46 46
47 47
48 48
49 49
50 50
51 51
52 52
53 53
54 54
55 55
56 56
57 57
58 58
59 59
60 60
61 61
62 62
63 63
64 64
65 65
66 66
67 67
68 68
69 69
70 70
71 71
72 72
73 73
74 74
75 75
76 76
77 77
78 78
79 79
80 80
81 81
82 82
83 83
84 84
85 85
86 86
87 87
88 88
89 89
90 90
91 91
92 92
93 93
94 94
95 95
96 96
97 97
98 98
99 99
100 100
read
clipped // for clipped unit cell display
evolver-2.30c.dfsg/fe/equi2.cmd 0000755 0001753 0001753 00000001571 11410765113 016541 0 ustar hazelsct hazelsct // equi2.cmd -- to color edges subject to equiangulation
// Programmer: Ken Brakke, brakke@susqu.edu, http://www.susqu.edu/brakke
// useage: showequi
showequi := {
local ecount, al,bl,cl,dl,el,nn;
ecount := 0;
foreach edge ee do
{ al := ee.length;
nn := 1;
foreach ee.facet ff do
{ foreach ff.edge fe do
{ if ( fe.id != ee.id ) then
{ if ( nn == 1 ) then bl := fe.length
else if ( nn == 2 ) then cl := fe.length
else if ( nn == 3 ) then dl := fe.length
else if ( nn == 4 ) then el := fe.length;
nn := nn + 1;
}
}
};
if ( nn == 5 ) then
if (bl^2+cl^2-al^2)/bl/cl + (dl^2+el^2-al^2)/dl/el < 0 then
{ set ee color green;
ecount := 1 + ecount
}
};
printf "Found %g edges.\n",ecount;
show_expr edges where 1
}
evolver-2.30c.dfsg/fe/catman.fe 0000644 0001753 0001753 00000004510 11410765113 016577 0 ustar hazelsct hazelsct // catman.fe
// Evolver datafile for catenoid with parameters as in Manual tutorial.
PARAMETER radius = 1 // ring radius; runtime adjustable
PARAMETER height = 0.55 // ring height; runtime adjustable
boundary 1 parameters 1 // upper ring; p1 is ring parameter
x1: radius * cos(p1)
x2: radius * sin(p1)
x3: height
boundary 2 parameters 1 // lower ring
x1: radius * cos(p1)
x2: radius * sin(p1)
x3: -height
vertices /* given by parameter value on a boundary */
1 0*pi/3 boundary 1 fixed
2 1*pi/3 boundary 1 fixed
3 2*pi/3 boundary 1 fixed
4 3*pi/3 boundary 1 fixed
5 4*pi/3 boundary 1 fixed
6 5*pi/3 boundary 1 fixed
7 0*pi/3 boundary 2 fixed
8 1*pi/3 boundary 2 fixed
9 2*pi/3 boundary 2 fixed
10 3*pi/3 boundary 2 fixed
11 4*pi/3 boundary 2 fixed
12 5*pi/3 boundary 2 fixed
edges /* given by endpoint vertices */
1 1 2 boundary 1 fixed
2 2 3 boundary 1 fixed
3 3 4 boundary 1 fixed
4 4 5 boundary 1 fixed
5 5 6 boundary 1 fixed
6 6 1 boundary 1 fixed
7 7 8 boundary 2 fixed
8 8 9 boundary 2 fixed
9 9 10 boundary 2 fixed
10 10 11 boundary 2 fixed
11 11 12 boundary 2 fixed
12 12 7 boundary 2 fixed
13 1 7
14 2 8
15 3 9
16 4 10
17 5 11
18 6 12
faces /* given by oriented edge list */
1 1 14 -7 -13
2 2 15 -8 -14
3 3 16 -9 -15
4 4 17 -10 -16
5 5 18 -11 -17
6 6 13 -12 -18
read
// Demonstrating saddle point due to triangulation arrangement.
// First setting parameters to stable values.
gogo := { g; u; r; g 50; // at this point have nearly a saddle point
g 200; // triangulation twists around to lower energy
}
// Faster version of the above using conjugate gradient
gogo2 := { g; u; r; U; g 25; // at this point have nearly a saddle point
g 35;
}
// High accuracy evolution, using higher-order Lagrange elements.
gogo3 := { u; rmax := cosh(height); recalc;
r; g 5; hessian;
r; g 5; hessian;
lagrange 2; g 5; hessian;
lagrange 4; g 5; hessian;
lagrange 6; g 5; hessian;
lagrange 8; g 5; hessian;
true_area := 2*pi*(height + 0.5*sinh(2*height));
printf"Difference from true area: %g\n",total_area - true_area;
}
evolver-2.30c.dfsg/fe/multiplicate.cmd 0000755 0001753 0001753 00000022050 11410765113 020203 0 ustar hazelsct hazelsct // multiplicate.cmd
// Surface Evolver script to create datafile with surface duplicated
// according to view transforms in effect. Writes datafile to stdout.
// Does not create new elements in current surface, since together
// with view transforms, that would result in quadratic explosion.
// WARNING: This loses all element attributes in the output datafile.
// But does preserve "edgetype" attribute
// Programmer: Ken Brakke, brakke@susqu.edu, http://www.susqu.edu/brakke
// usage: multiplicate >>> "newdatafile.fe"
define edge attribute edgetype integer // in case doesn't exist
eps := 1e-4 // tolerance for identifying vertices
// Hash table for finding identified vertices. Generates hash value
// from skew plane.
mskew1 := 0.361234123413728768
mskew2 := 0.725423451231725277
mskew3 := 0.5227723243451234514
vertex_hash_init := {
vertex_hash_table_size := vertex_count*transform_count;
define vertex_hash_table integer[vertex_hash_table_size];
define vertex_hash_chain integer[vertex_hash_table_size];
define newcoord real[vertex_hash_table_size][3];
vertex_entry_count := 0;
}
// deallocate memory
vertex_hash_end := {
define vertex_hash_table integer[0];
define vertex_hash_chain integer[0];
define newcoord real[0][0];
}
// Returns sequential number of found or new vertex.
function integer vertex_hash_add(real xx, real yy, real zz)
{ local hashval,hashspot;
local vnum,dist;
hashval := floor((mskew1*xx + mskew2*yy + mskew3*zz)/eps);
hashspot := hashval imod vertex_hash_table_size;
// See if there
for ( vnum := vertex_hash_table[hashspot] ; vnum != 0 ;
vnum := vertex_hash_chain[vnum] )
{
dist := sqrt((xx-newcoord[vnum][1])^2 + (yy-newcoord[vnum][2])^2 +
(zz-newcoord[vnum][3])^2);
if dist < eps then return vnum;
};
// Not there, so add
vertex_entry_count += 1;
vnum := vertex_entry_count;
vertex_hash_chain[vnum] := vertex_hash_table[hashspot];
vertex_hash_table[hashspot] := vnum;
newcoord[vnum][1] := xx;
newcoord[vnum][2] := yy;
newcoord[vnum][3] := zz;
return vnum;
}
// Hash table for finding identified edges.
edge_hash_init := {
edge_hash_table_size := edge_count*transform_count;
define edge_hash_table integer[edge_hash_table_size];
define edge_hash_chain integer[edge_hash_table_size];
define new_edge_verts integer[edge_hash_table_size][2];
edge_entry_count := 0;
}
// deallocate memory
edge_hash_end := {
define edge_hash_table integer[0];
define edge_hash_chain integer[0];
define new_edge_verts integer[0][0];
}
// Edge hasher. Returns sequential number (signed) of found or new edge.
function integer edge_hash_add(integer tailv, integer headv)
{ local temp,signflag;
local hashval,hashspot;
local edgenum;
// get vertices in canonical order
if tailv > headv then
{ temp := tailv;
tailv := headv;
headv := temp;
signflag := -1;
}
else signflag := 1;
hashval := tailv*737 + headv;
hashspot := hashval imod edge_hash_table_size;
// See if there
for ( edgenum := edge_hash_table[hashspot] ; edgenum != 0 ;
edgenum := edge_hash_chain[edgenum] )
{
if (tailv == new_edge_verts[edgenum][1]) and
(headv == new_edge_verts[edgenum][2])
then return signflag*edgenum;
};
// Not there, so add
edge_entry_count += 1;
edgenum := edge_entry_count;
edge_hash_chain[edgenum] := edge_hash_table[hashspot];
edge_hash_table[hashspot] := edgenum;
new_edge_verts[edgenum][1] := tailv;
new_edge_verts[edgenum][2] := headv;
return signflag*edgenum;
}
multiplicate := {
local tcount,high_vertex,vx,vy,vz;
local high_edge,thistail,thishead,fstride,tdet,edge1,edge2,edge3;
list topinfo;
define vertex attribute tx real[transform_count];
define vertex attribute ty real[transform_count];
define vertex attribute tz real[transform_count];
define vertex attribute valias integer[transform_count];
define edge attribute ehead integer[transform_count];
define edge attribute etail integer[transform_count];
define edge attribute ealias integer[transform_count];
printf "\nVertices\n";
vertex_hash_init;
tcount := 1;
high_vertex := 0;
while ( tcount <= transform_count ) do
{ foreach vertex vv do
{
vx := view_transforms[tcount][1][1]*vv.x
+ view_transforms[tcount][1][2]*vv.y
+ view_transforms[tcount][1][3]*vv.z
+ view_transforms[tcount][1][4]*1;
vy := view_transforms[tcount][2][1]*vv.x
+ view_transforms[tcount][2][2]*vv.y
+ view_transforms[tcount][2][3]*vv.z
+ view_transforms[tcount][2][4]*1;
vz := view_transforms[tcount][3][1]*vv.x
+ view_transforms[tcount][3][2]*vv.y
+ view_transforms[tcount][3][3]*vv.z
+ view_transforms[tcount][3][4]*1;
vv.tx[tcount] := vx; vv.ty[tcount] := vy; vv.tz[tcount] := vz;
// search for alias
vv.valias[tcount] := vertex_hash_add(vx,vy,vz);
if vv.valias[tcount] > high_vertex then
{ printf "%d %18.15f %18.15f %18.15f ",vv.valias[tcount],
vx,vy,vz;
printf "\n";
high_vertex := vv.valias[tcount];
};
};
tcount += 1;
};
vertex_hash_end;
printf "\nEdges\n";
tcount := 1;
edge_hash_init;
high_edge := 0;
while ( tcount <= transform_count ) do
{ foreach edge ee do
{
thistail := vertex[ee.vertex[1].id].valias[tcount];
thishead := vertex[ee.vertex[2].id].valias[tcount];
ee.ehead[tcount] := thishead;
ee.etail[tcount] := thistail;
// search for aliases
ee.ealias[tcount] := edge_hash_add(thistail,thishead);
if ( abs(ee.ealias[tcount]) > high_edge ) then
{ printf "%d %d %d edgetype %d",abs(ee.ealias[tcount]),
minimum(thistail,thishead),maximum(thistail,thishead),edgetype;
if ee.bare then printf " bare ";
printf "\n";
high_edge := abs(ee.ealias[tcount]);
};
};
tcount += 1;
};
edge_hash_end;
printf "\nFaces\n";
fstride := max(facet,id);
tcount := 1;
while ( tcount <= transform_count ) do
{ tdet := view_transforms[tcount][1][1]*
(view_transforms[tcount][2][2]*view_transforms[tcount][3][3]
- view_transforms[tcount][3][2]*view_transforms[tcount][2][3])
- view_transforms[tcount][1][2]*
(view_transforms[tcount][2][1]*view_transforms[tcount][3][3]
- view_transforms[tcount][3][1]*view_transforms[tcount][2][3])
+ view_transforms[tcount][1][3]*
(view_transforms[tcount][2][1]*view_transforms[tcount][3][2]
- view_transforms[tcount][3][1]*view_transforms[tcount][2][2]);
foreach facet ff do
{ edge1 := edge[ff.edge[1].id].ealias[tcount];
edge2 := edge[ff.edge[2].id].ealias[tcount];
edge3 := edge[ff.edge[3].id].ealias[tcount];
if ( view_transform_swap_colors[tcount] != (tdet < 0.0) ) then
// inverted
printf "%d %d %d %d\n",ff.id + (tcount-1)*fstride,
((ff.edge[3].oid > 0) ? -edge3 : edge3),
((ff.edge[2].oid > 0) ? -edge2 : edge2),
((ff.edge[1].oid > 0) ? -edge1 : edge1)
else
printf "%d %d %d %d\n",ff.id + (tcount-1)*fstride,
((ff.edge[1].oid > 0) ? edge1 : -edge1),
((ff.edge[2].oid > 0) ? edge2 : -edge2),
((ff.edge[3].oid > 0) ? edge3 : -edge3);
};
tcount += 1;
};
// not listing bottominfo on purpose; too much extraneous stuff
// free attribute storage
define vertex attribute tx real[0];
define vertex attribute ty real[0];
define vertex attribute tz real[0];
define vertex attribute valias integer[0];
define edge attribute ehead integer[0];
define edge attribute etail integer[0];
define edge attribute ealias integer[0];
}
aa := 1
pview := {
printf "%f %f %f %f\n",view_transforms[aa][1][1],view_transforms[aa][1][2],
view_transforms[aa][1][3],view_transforms[aa][1][4];
printf "%f %f %f %f\n",view_transforms[aa][2][1],view_transforms[aa][2][2],
view_transforms[aa][2][3],view_transforms[aa][2][4];
printf "%f %f %f %f\n",view_transforms[aa][3][1],view_transforms[aa][3][2],
view_transforms[aa][3][3],view_transforms[aa][3][4];
printf "%f %f %f %f\n",view_transforms[aa][4][1],view_transforms[aa][4][2],
view_transforms[aa][4][3],view_transforms[aa][4][4];
}
// Paste things together that didn't get pasted, by finding edges that
// come out of vertices in the same direction.
paste := {
local paste_count;
paste_count := 0; // track how many found, so know when no more left
foreach vertex vv do
{ foreach vv.edge ee do
{
foreach vv.edge eee do
{ if ee.id == eee.id then continue;
if (ee.x-eee.x)^2 + (ee.y-eee.y)^2 + (ee.z-eee.z)^2 < eps^2 then
{ edge_merge(ee.oid,eee.oid);
paste_count += 1;
break;
}
}
}
};
printf "Edges pasted: %d\n",paste_count;
}
// usage: Set view transforms as desired, then do
// multiplicate >>> "newdatafile.fe"
evolver-2.30c.dfsg/fe/metric.fe 0000644 0001753 0001753 00000000734 11410765113 016623 0 ustar hazelsct hazelsct // metric.fe
// Demonstration of background metric with strings
// Metric turns punctured plane into catenoid. Initial string
// shrinks to loop around throat. Note that graphing uses just
// the plane coordinates without metric.
SPACE_DIMENSION 2
STRING
#define G11 (1 + 1/(x^2 + y^2))^2
METRIC
G11 0
0 G11
vertices
1 1 0
2 0 2
3 -2 0
4 0 -1
edges
1 1 2
2 2 3
3 3 4
4 4 1
read
// Typical evolution
gogo := { g 5; r; g 5; r; g 5; r; g 5; }
evolver-2.30c.dfsg/fe/slice2.cmd 0000755 0001753 0001753 00000004356 11410765113 016701 0 ustar hazelsct hazelsct // slice2.cmd --- produce intersection of surface with plane
// plane eq: aa*x + bb*y + cc*z = dd
// output: length of slice, and area inside slice.
// Does not modify surface.
// Note all area inside slice is counted as positive!
// Do not to slice exactly through vertices!! Avoid special
// values for dd like 0 or .5!
// Fixed to do oriented facets of a particular body.
// Usage: set plane coefficients, then do slice2(body number).
// Results: Intersection length printed out, left in variable lensum.
// Programmer: Ken Brakke, brakke@susqu.edu, http://www.susqu.edu/brakke
procedure slice2(integer body_num) := {
local any,xx1,yy1,zz1,xx2,yy2,zz2;
local denom,lambda,zaa,zbb,darea;
lensum := 0; areasum := 0;
xb := 0; yb := 0; zb := 0; // just for declaration before use.
foreach body[body_num].facet ff do
{ any := 0;
foreach ff.edge ee do
{
xx1 := ee.vertex[1].x;
yy1 := ee.vertex[1].y;
zz1 := ee.vertex[1].z;
xx2 := ee.vertex[2].x;
yy2 := ee.vertex[2].y;
zz2 := ee.vertex[2].z;
denom := aa*(xx1-xx2)+bb*(yy1-yy2)+cc*(zz1-zz2);
if ( denom != 0.0 ) then
{
lambda := (dd-aa*xx2-bb*yy2-cc*zz2)/denom;
if ( (lambda >= 0) and (lambda <= 1) ) then
{
xa := xb; ya := yb; za := zb;
xb := lambda*xx1+(1-lambda)*xx2;
yb := lambda*yy1+(1-lambda)*yy2;
zb := lambda*zz1+(1-lambda)*zz2;
any := any+1;
}
}
} ;
if any == 2 then
{
local triple;
dx := xa-xb; dy := ya-yb; dz := za - zb;
lensum := lensum + sqrt(dx^2+dy^2+dz^2);
zaa := za - dd/cc; zbb := zb - dd/cc;
fx := ff.x; fy := ff.y; fz := ff.z;
triple := fx*(dy*cc-dz*bb)+fy*(dz*aa-dx*cc)+fz*(dx*bb-dy*aa);
darea := (xa*yb-xb*ya)/2;
if ( triple > 0 ) then areasum := areasum + darea
else areasum := areasum - darea;
}
};
areasum := areasum*sqrt(aa*aa+bb*bb+cc*cc)/cc;
printf "Circumference: %18.15g Area: %18.15g\n",lensum,areasum;
} // end slice
evolver-2.30c.dfsg/fe/quadint2.cmd 0000755 0001753 0001753 00000015570 11410765113 017247 0 ustar hazelsct hazelsct // quadint2.cmd
// For detecting intersection of quadratic facets in 3D
// Not suitable for torus model.
// Needs quadbbox.cmd to be loaded first.
// Programmer: Ken Brakke, brakke@susqu.edu, http://www.susqu.edu/brakke
// Usage: quadmeet
// Prints id numbers of pairs of intersecting facets and colors them green.
a_refine_order := 4
b_refine_order := 5
eps := 1e-10 // tolerance for being equal to zero
ax := 0; bx := 0; cx := 0; ay := 0; by := 0; cy := 0; az := 0; bz := 0; cz := 0;
px := 0; py := 0; pz := 0; qx := 0; qy := 0; qz:= 0;
uuu := 0; vvv := 0;
xa1 := 0; xa2 := 0; xa3 := 0; xa4 := 0; xa5 := 0; xa6 := 0
ya1 := 0; ya2 := 0; ya3 := 0; ya4 := 0; ya5 := 0; ya6 := 0
za1 := 0; za2 := 0; za3 := 0; za4 := 0; za5 := 0; za6 := 0
intersection_found := 0;
// detection of triangle and edge intersection
detect := {
local acx,acy,acz,bcx,bcy,bcz,qpx,qpy,qpz,qcx,qcy,qcz;
local denom,lambda,mu,sigma;
do {
acx := ax-cx; acy := ay-cy; acz := az-cz;
bcx := bx-cx; bcy := by-cy; bcz := bz-cz;
qpx := qx-px; qpy := qy-py; qpz := qz-pz;
qcx := qx-cx; qcy := qy-cy; qcz := qz-cz;
denom := qpx*(acy*bcz-acz*bcy) - qpy*(acx*bcz-acz*bcx)
+ qpz*(acx*bcy-acy*bcx);
if ( abs(denom) < eps ) then break;
lambda := (qpx*(qcy*bcz-qcz*bcy) - qpy*(qcx*bcz-qcz*bcx)
+ qpz*(qcx*bcy-qcy*bcx))/denom;
if ( lambda <= eps ) then break;
mu := (qpx*(acy*qcz-acz*qcy) - qpy*(acx*qcz-acz*qcx)
+ qpz*(acx*qcy-acy*qcx))/denom;
if ( mu <= eps ) then break;
if ( lambda + mu > 1-eps ) then break;
sigma := (qcx*(acy*bcz-acz*bcy) - qcy*(acx*bcz-acz*bcx)
+ qcz*(acx*bcy-acy*bcx))/denom;
if ( (sigma <= eps) or (sigma > 1-eps) ) then break;
// now have intersection
intersection_found := 1;
} while 0; // so we could use break
} // end detect
calccoords := {
xx := 0.5*(uuu+vvv-1)*(uuu+vvv-2)*xa1 + uuu*(2-uuu-vvv)*xa2
+ 0.5*uuu*(uuu-1)*xa3 + vvv*(2-uuu-vvv)*xa4
+ uuu*vvv*xa5 + 0.5*vvv*(vvv-1)*xa6;
yy := 0.5*(uuu+vvv-1)*(uuu+vvv-2)*ya1 + uuu*(2-uuu-vvv)*ya2
+ 0.5*uuu*(uuu-1)*ya3 + vvv*(2-uuu-vvv)*ya4
+ uuu*vvv*ya5 + 0.5*vvv*(vvv-1)*ya6;
zz := 0.5*(uuu+vvv-1)*(uuu+vvv-2)*za1 + uuu*(2-uuu-vvv)*za2
+ 0.5*uuu*(uuu-1)*za3 + vvv*(2-uuu-vvv)*za4
+ uuu*vvv*za5 + 0.5*vvv*(vvv-1)*za6;
} // end calccoords
refine_and_test := {
// Test intersections of planar subtriangles and sub edges
adelta := 2/a_refine_order;
bdelta := 2/b_refine_order;
ua := 0;
while ( ua < 1.9999 ) do
{ va := 0;
while ( va < 1.9999 - ua ) do
{ uuu := ua; vvv := va; calccoords; ax := xx; ay := yy; az := zz;
uuu := ua+adelta; vvv := va; calccoords; bx := xx; by := yy; bz := zz;
uuu := ua; vvv := va+adelta; calccoords; cx := xx; cy := yy; cz := zz;
ub := 0;
while ( ub < 1.9999 ) do
{ vb := 0;
while ( vb < 1.9999 - ub ) do
{
uuu := ub; vvv := vb; calccoords; px := xx; py := yy; pz := zz;
uuu := ub+bdelta; vvv := vb; calccoords; qx := xx; qy := yy; qz := zz;
detect; if intersection_found then break;
uuu := ub; vvv := vb+bdelta; calccoords; px := xx; py := yy; pz := zz;
detect; if intersection_found then break;
uuu := ub; vvv := vb; calccoords; qx := xx; qy := yy; qz := zz;
detect; if intersection_found then break;
vb := vb + bdelta;
};
if intersection_found then break;
ub := ub + bdelta;
};
if intersection_found then break;
va := va + adelta;
};
if intersection_found then break;
ua := ua + adelta;
}
} // end refine_and_test
quadmeet := {
intersect_total := 0;
fboxes; // find facet bounding boxes
// test all facet pairs
foreach facet fa do
{ foreach facet fb where fb.id > fa.id do
{ // check adjacency
if ( fa.vertex[1].id == fb.vertex[1].id ) then continue;
if ( fa.vertex[2].id == fb.vertex[1].id ) then continue;
if ( fa.vertex[3].id == fb.vertex[1].id ) then continue;
if ( fa.vertex[1].id == fb.vertex[2].id ) then continue;
if ( fa.vertex[2].id == fb.vertex[2].id ) then continue;
if ( fa.vertex[3].id == fb.vertex[2].id ) then continue;
if ( fa.vertex[1].id == fb.vertex[3].id ) then continue;
if ( fa.vertex[2].id == fb.vertex[3].id ) then continue;
if ( fa.vertex[3].id == fb.vertex[3].id ) then continue;
// first, check bounding boxes
if ( fb.fbox[1] >= fa.fbox[2] or
fb.fbox[2] <= fa.fbox[1] or
fb.fbox[3] >= fa.fbox[4] or
fb.fbox[4] <= fa.fbox[3] or
fb.fbox[5] >= fa.fbox[6] or
fb.fbox[6] <= fa.fbox[5] ) then continue;
// extract coordinates
xa1 := fa.edge[1].vertex[1].x;
xa2 := fa.edge[1].vertex[3].x;
xa3 := fa.edge[1].vertex[2].x;
xa4 := fa.edge[3].vertex[3].x;
xa5 := fa.edge[2].vertex[3].x;
xa6 := fa.edge[2].vertex[2].x;
ya1 := fa.edge[1].vertex[1].y;
ya2 := fa.edge[1].vertex[3].y;
ya3 := fa.edge[1].vertex[2].y;
ya4 := fa.edge[3].vertex[3].y;
ya5 := fa.edge[2].vertex[3].y;
ya6 := fa.edge[2].vertex[2].y;
za1 := fa.edge[1].vertex[1].z;
za2 := fa.edge[1].vertex[3].z;
za3 := fa.edge[1].vertex[2].z;
za4 := fa.edge[3].vertex[3].z;
za5 := fa.edge[2].vertex[3].z;
za6 := fa.edge[2].vertex[2].z;
xb1 := fb.edge[1].vertex[1].x;
xb2 := fb.edge[1].vertex[3].x;
xb3 := fb.edge[1].vertex[2].x;
xb4 := fb.edge[3].vertex[3].x;
xb5 := fb.edge[2].vertex[3].x;
xb6 := fb.edge[2].vertex[2].x;
yb1 := fb.edge[1].vertex[1].y;
yb2 := fb.edge[1].vertex[3].y;
yb3 := fb.edge[1].vertex[2].y;
yb4 := fb.edge[3].vertex[3].y;
yb5 := fb.edge[2].vertex[3].y;
yb6 := fb.edge[2].vertex[2].y;
zb1 := fb.edge[1].vertex[1].z;
zb2 := fb.edge[1].vertex[3].z;
zb3 := fb.edge[1].vertex[2].z;
zb4 := fb.edge[3].vertex[3].z;
zb5 := fb.edge[2].vertex[3].z;
zb6 := fb.edge[2].vertex[2].z;
refine_and_test;
if intersection_found then
{ intersect_total := intersect_total + 1;
set fa color green; set fb color green;
printf "Facets %g and %g intersect.\n",fa.id,fb.id;
}
}
};
printf "Intersections found: %g\n",intersect_total;
} // end quadmeet
evolver-2.30c.dfsg/fe/gaussequi.cmd 0000755 0001753 0001753 00000003277 11410765113 017527 0 ustar hazelsct hazelsct // gaussequi.cmd
// Equiangulation using Gauss map for swap criterion.
// But has problems; can produce zero area facets. Also, swapping an
// edge changes the Gauss map, so maybe things don't improve.
// Programmer: Ken Brakke, brakke@susqu.edu, http://www.susqu.edu/brakke
// Usage: gaussequi
gaussequi := {
local ax,ay,az,bx,by,bz,ffnum,cx,cy,cz,dx,dy,dz,aa,bb,cc,dd,ee;
swapcount := 0;
foreach edge eee where not fixed and valence == 2 do
{ ax := eee.vertex[1].vertexnormal[1];
ay := eee.vertex[1].vertexnormal[2];
az := eee.vertex[1].vertexnormal[3];
bx := eee.vertex[2].vertexnormal[1];
by := eee.vertex[2].vertexnormal[2];
bz := eee.vertex[2].vertexnormal[3];
ffnum := eee.facet[1].id;
foreach facet[ffnum].vertex vv do
{ if vv.id != eee.vertex[1].id and vv.id != eee.vertex[2].id then
{ vvnum := vv.id; break; }
};
cx := vertex[vvnum].vertexnormal[1];
cy := vertex[vvnum].vertexnormal[2];
cz := vertex[vvnum].vertexnormal[3];
ffnum := eee.facet[2].id;
foreach facet[ffnum].vertex vv do
{ if vv.id != eee.vertex[1].id and vv.id != eee.vertex[2].id then
{ vvnum := vv.id; break; }
};
dx := vertex[vvnum].vertexnormal[1];
dy := vertex[vvnum].vertexnormal[2];
dz := vertex[vvnum].vertexnormal[3];
aa := (ax-bx)^2+(ay-by)^2+(az-bz)^2;
bb := (ax-cx)^2+(ay-cy)^2+(az-cz)^2;
cc := (bx-cx)^2+(by-cy)^2+(bz-cz)^2;
dd := (ax-dx)^2+(ay-dy)^2+(az-dz)^2;
ee := (bx-dx)^2+(by-dy)^2+(bz-dz)^2;
if ( (bb+cc-aa)*sqrt(dd*ee) + (dd+ee-aa)*sqrt(bb*cc) < 0 ) then
{ edgeswap eee;
swapcount += 1;
};
};
printf "Edges gaussequi swapped: %d\n",swapcount;
}
evolver-2.30c.dfsg/fe/rotate.cmd 0000755 0001753 0001753 00000000736 11410765113 017014 0 ustar hazelsct hazelsct // rotate.cmd
// Surface Evolver procedure to rotate unfixed vertices by angle about z axis.
// Programmer: Ken Brakke, brakke@susqu.edu, http://www.susqu.edu/brakke
// Usage: rotate(angle)
// where angle is in radians.
procedure rotate(real roth) := {
local sss,ccc,rrad,olds;
sss := sin(roth); ccc := cos(roth);
foreach vertex vv where not fixed do
{ rrad := vv.x^2+vv.y^2;
oldx := vv.x;
set vv x vv.x*ccc-vv.y*sss;
set vv y oldx*sss+vv.y*ccc;
}
}
evolver-2.30c.dfsg/fe/reorder.cmd 0000755 0001753 0001753 00000001070 11410765113 017150 0 ustar hazelsct hazelsct // reorder.cmd
define vertex attribute vertex_order_key real
define edge attribute edge_order_key real
define facet attribute facet_order_key real
define body attribute body_order_key real
define facetedge attribute facetedge_order_key real
reorder := {
set vertex vertex_order_key x+y+z;
set edge ee edge_order_key min(ee.vertex,vertex_order_key);
set facetedge fe facetedge_order_key fe.edge[1].edge_order_key;
set facet ff facet_order_key min(ff.vertex,vertex_order_key);
set body bb body_order_key min(bb.facet,facet_order_key);
reorder_storage;
}
evolver-2.30c.dfsg/fe/knotty.fe 0000644 0001753 0001753 00000007671 11410765113 016677 0 ustar hazelsct hazelsct // knotty.fe
// Evolver data for 3,2 torus knot (trefoil) with various knot energies.
// You need to set one type of energy and one type of length constraint;
// see the set_* commands in the "read" section of the datafile.
// Not all combinations are workable.
string // this is a 1D surface
parameter maj_r = 2 // torus major radius
parameter min_r = 0.5 // torus minor radius
boundary 1 parameter 1 // parametric curve around torus
x1: cos(2*p1)*(maj_r + min_r*cos(3*p1))
x2: sin(2*p1)*(maj_r + min_r*cos(3*p1))
x3: min_r*sin(3*p1)
// Here follow six different types of energy. Switch between them
// with the set_* commands in the bottom section of this datafile.
// elastic bending energy, i.e. squared curvature
quantity bending_energy ENERGY modulus 0 method sqcurve_string global
// conducting wire vertex energy
quantity conduct_energy ENERGY modulus 1 method knot_energy global
// insulating wire vertex energy
quantity insul_energy ENERGY modulus 0 method edge_knot_energy global
// Greg Buck's 1/(d1+d2+d3+d4-2(L1+L2)) energy
quantity buck_energy ENERGY modulus 0 method buck_knot_energy global
// have to start with modulus 0 since edges too long at start */
// Greg Buck's normal projection energy
quantity proj_energy ENERGY modulus 0 method proj_knot_energy global
// Peter Doyle's conformal circle energy
quantity circle_energy ENERGY modulus 0 method circle_knot_energy global
// Here follow three ways to control the length of edges.
// Switch between them with the set_* commands below.
// Elastic stretching energy to encourage edges to all have the same length.
// Use "hooke_length := value" command to set hooke_length to desired
// edge length
quantity hooke ENERGY modulus 0 method hooke_energy global
// Individually set edge equilibrium lengths.
// Use "set edge hooke_size expr" to set desired edge lengths
// When used, the modulus needs to be set high, like 1000 or 10000,
// to provide decent stiffness.
define edge attribute hooke_size real
quantity hooke2 ENERGY modulus 0 method hooke2_energy global
// to keep total length fixed
quantity knot_length FIXED = 24 modulus 1 method edge_tension global
vertices
1 0.0*pi boundary 1
2 0.2*pi boundary 1
3 0.4*pi boundary 1
4 0.6*pi boundary 1
5 0.8*pi boundary 1
6 1.0*pi boundary 1
7 1.2*pi boundary 1
8 1.4*pi boundary 1
9 1.6*pi boundary 1
10 1.8*pi boundary 1
edges
1 1 2 boundary 1
2 2 3 boundary 1
3 3 4 boundary 1
4 4 5 boundary 1
5 5 6 boundary 1
6 6 7 boundary 1
7 7 8 boundary 1
8 8 9 boundary 1
9 9 10 boundary 1
10 10 1 boundary 1
read // some initialization commands
r 2 // refining twice produces 40 vertices
unset vertices boundary 1 // release from parametric curve
unset edges boundary 1
set edge tension 0 // get rid of default tension energy
set edge color white where id <= edge_count/2 // dashed coloring
// Set all quantity moduli to zero
zero_moduli := {
bending_energy.modulus := 0;
conduct_energy.modulus := 0;
insul_energy.modulus := 0;
buck_energy.modulus := 0;
proj_energy.modulus := 0;
circle_energy.modulus := 0;
}
// Set up individual types of energy
set_bending := { zero_moduli; bending_energy.modulus := 1; }
set_conduct := { zero_moduli; conduct_energy.modulus := 1; }
set_insul := { zero_moduli; insul_energy.modulus := 1; }
set_buck := { zero_moduli; buck_energy.modulus := 1; }
set_proj := { zero_moduli; proj_energy.modulus := 1; }
set_circle := { zero_moduli; circle_energy.modulus := 1; }
// Set up type of length constraint
hooke_length := total_length/edge_count;
set edge hooke_size total_length/edge_count;
set_length := { fix knot_length; hooke.modulus := 0; hooke2.modulus := 0; }
set_hooke := { unfix knot_length; hooke.modulus := 1000; hooke2.modulus := 0; }
set_hooke2 := { unfix knot_length; hooke.modulus := 0; hooke2.modulus := 1000; }
// Sample evolution
gogo := { g 50; U; g 50; }
evolver-2.30c.dfsg/fe/zebra.cmd 0000755 0001753 0001753 00000003011 11410765113 016606 0 ustar hazelsct hazelsct // zebra.cmd
// Evolver command to alternately color string edges black and white
// Usage: Set color1 and color2 to the two colors you want, if the
// default black and white are not suitable. Then run "zebra".
// Programmer: Ken Brakke, brakke@susqu.edu, http://www.susqu.edu/brakke
color1 := white
color2 := black
zebra := {
local ecount,first_e,v_id,zcolor,zinx,e_id;
ecount := 0; // for safety
// Look for valence 2 vertices with same color edges and
// propagate zebra coloring in both directions.
foreach vertex vv where valence==2 and vv.edge[1].color == vv.edge[2].color do
{
first_e := vv.edge[1].oid;
v_id := vv.id;
zcolor := color1;
for ( zinx := 1 ; zinx <= 2 ; zinx += 1 )
{
// follow connected edges
e_id := first_e;
do
{ set edge[e_id] color zcolor;
v_id := edge[e_id].vertex[2].id;
if vertex[v_id].valence != 2 then break;
if vertex[v_id].edge[1].oid == -e_id then
e_id := vertex[v_id].edge[2].oid
else
e_id := vertex[v_id].edge[1].oid;
zcolor := (zcolor == color1) ? color2 : color1;
ecount := ecount + 1;
} while ( (v_id != vv.id) and (ecount <= edge_count) );
if ( v_id == vv.id ) then break; // don't need to go around the other way
// set things up to go around other way next time through the loop.
v_id := vv.id;
zcolor := color2;
first_e := vv.edge[2].oid;
}
} // end valence 2 vertex loop
} // end zebra
evolver-2.30c.dfsg/fe/mylarcube.fe 0000644 0001753 0001753 00000014636 11410765113 017331 0 ustar hazelsct hazelsct // mylarcube.fe
// By Kenneth Brakke, Feb. 17, 2002
// Evolver data for mylar cube. Idea is to deform cube
// without stretching to maximize volume. Implemented with
// relaxed_elastic_A method, which permits a little stretching, but
// shrinks freely. Can crank up the elastic modulus to get
// effective no stretching. The relaxed_elastic_A method calculates
// the Cauchy-Green strain tensor of a facet, and then uses
// Poisson's ratio to get the stress tensor. Then it calculates
// the stress eigenvalues, and assigns energy proportional to the
// square of positive eigenvalues, but zero energy for negative
// eigenvalues. So it permits effective wrinkling. The original
// unstretched shape of a facet is remembered in an extra facet
// attribute named form_factors, which has the components of the
// Gram matrix of the unstretched facet. This datafile assumes the
// initial surface is unstretched, and sets the form_factors in
// the "read" section below. To recompute form factors after refining,
// there is also a vertex attribute that holds the unstretched
// vertex coordinates. The "r" command has been redefined in the
// "read" section to properly adjust the form factors. DO NOT refine
// or modify the triangulation in any other way than using the "r"
// command, unless you want to take responsibility for fixing up
// the form factors.
// The Poisson ratio in this datafile is set to be 0.80 in the "read"
// section. This was the Poisson ratio used in the project that
// relaxed_elastic_A was originally developed for: modeling high-altitude
// balloons. A couple of test runs with lower Poisson ratio led to
// indefinite hessians at the end, so I am leaving the ratio as 0.80.
// Evolving hints: See the sample evolution "gogo" below. The idea is
// to ramp up the elastic modulus as you refine and approach the final
// shape. For final convergence, use "hessian_seek" instead of "hessian",
// since "hessian" has a tendency to blow up the surface here, and
// "hessian_seek" prevents that by doing a minimum-energy search along
// the direction to the putative hessian minimum. Note that the energy
// contribution of the elastic is inversely proportional to the elastic
// modulus. I'm not sure how high you can get the modulus effectively;
// at least 1000000. Extrapolate to infinite modulus for unstretchable
// mylar.
// If you want confirmation at the end that there is little stretching
// going on, the command "echeck" below will print out a histogram of
// edge stretch factors.
// Do not try to do quadratic or lagrange models; relaxed_elastic_A is
// defined only for the linear model.
/***************************************************************************/
// Set volume to be maximized. Do this by setting energy to negative
// volume, since Evolver minimizes energy.
quantity cube_volume energy modulus -1 method facet_volume global
// Elastic energy.
// Stuff to do relaxed_elastic_A method
define facet attribute poisson_ratio real
// For defining unstretched facet shape
define facet attribute form_factors real[3]
// For resetting form_factors in refining
define vertex attribute ref_coord real[3]
define vertex attribute old_vid integer
define edge attribute old_eid integer
// This is the key energy to permit wrinkling but discourage stretching.
quantity stretch energy modulus 10 method relaxed_elastic_A global
// For components of stress
quantity stretch1 info_only method relaxed_elastic1_A global
quantity stretch2 info_only method relaxed_elastic2_A global
vertices
1 0.0 0.0 0.0
2 1.0 0.0 0.0
3 1.0 1.0 0.0
4 0.0 1.0 0.0
5 0.0 0.0 1.0
6 1.0 0.0 1.0
7 1.0 1.0 1.0
8 0.0 1.0 1.0
edges /* given by endpoints and attribute */
1 1 2
2 2 3
3 3 4
4 4 1
5 5 6
6 6 7
7 7 8
8 8 5
9 1 5
10 2 6
11 3 7
12 4 8
faces /* given by oriented edge loop */
1 1 10 -5 -9 tension 0
2 2 11 -6 -10 tension 0
3 3 12 -7 -11 tension 0
4 4 9 -8 -12 tension 0
5 5 6 7 8 tension 0
6 -4 -3 -2 -1 tension 0
bodies /* one body, defined by its oriented faces */
1 1 2 3 4 5 6
read
// refine original edges so better suited to detect creases
refine edge where id >= 1 and id <=12
set facet poisson_ratio 0.80
set vertex ref_coord[1] x;
set vertex ref_coord[2] y;
set vertex ref_coord[3] z;
// Set form factors so initial cube is unstretched.
set_form_factors := {
foreach facet ff do
{ set ff.form_factors[1]
(ff.vertex[2].ref_coord[1] - ff.vertex[1].ref_coord[1])^2
+ (ff.vertex[2].ref_coord[2] - ff.vertex[1].ref_coord[2])^2
+ (ff.vertex[2].ref_coord[3] - ff.vertex[1].ref_coord[3])^2;
set ff.form_factors[2]
(ff.vertex[2].ref_coord[1] - ff.vertex[1].ref_coord[1])
*(ff.vertex[3].ref_coord[1] - ff.vertex[1].ref_coord[1])
+ (ff.vertex[2].ref_coord[2] - ff.vertex[1].ref_coord[2])
*(ff.vertex[3].ref_coord[2] - ff.vertex[1].ref_coord[2])
+ (ff.vertex[2].ref_coord[3] - ff.vertex[1].ref_coord[3])
*(ff.vertex[3].ref_coord[3] - ff.vertex[1].ref_coord[3]);
set ff.form_factors[3]
(ff.vertex[3].ref_coord[1] - ff.vertex[1].ref_coord[1])^2
+ (ff.vertex[3].ref_coord[2] - ff.vertex[1].ref_coord[2])^2
+ (ff.vertex[3].ref_coord[3] - ff.vertex[1].ref_coord[3])^2;
}
}
set_form_factors;
// redefine the "r" command to adjust form factors.
r :::= {
set vertex old_vid id;
set edge old_eid id;
'r';
foreach vertex vv where old_vid == 0 do
{ vv.ref_coord[1] :=
avg(vv.edge ee where old_eid != 0,sum(ee.vertex where old_vid != 0,
ref_coord[1]));
vv.ref_coord[2] :=
avg(vv.edge ee where old_eid != 0,sum(ee.vertex where old_vid != 0,
ref_coord[2]));
vv.ref_coord[3] :=
avg(vv.edge ee where old_eid != 0,sum(ee.vertex where old_vid != 0,
ref_coord[3]));
};
set_form_factors;
recalc;
}
// check of how edge lengths stretched
echeck := { histogram(edge ee, ee.length/sqrt(
(ee.vertex[2].ref_coord[1] - ee.vertex[1].ref_coord[1])^2
+ (ee.vertex[2].ref_coord[2] - ee.vertex[1].ref_coord[2])^2
+ (ee.vertex[2].ref_coord[3] - ee.vertex[1].ref_coord[3])^2));
}
// Typical evolution
gogo := { g 10; r; g 10; stretch.modulus := 100; g 10; r; g 10;
conj_grad; g 20; r; g 50;
stretch.modulus := 1000; g 50;
stretch.modulus := 10000; g 150;
g 200; hessian_seek; hessian_seek; hessian_seek; hessian_seek;
}
evolver-2.30c.dfsg/fe/dirichlet_to_disk.cmd 0000755 0001753 0001753 00000012601 11410765113 021173 0 ustar hazelsct hazelsct // dirichlet_to_disk.cmd
// Programmer: Ken Brakke, brakke@susqu.edu, http://www.susqu.edu/brakke
// For mapping simply connected regions to unit disk minimizing Dirichlet
// energy to get conformal mappings.
// Prerequisites: Dirichlet energy defined, but no others.
// Usage: Remove all constraints and boundaries. Run to_disk. Then evolve.
define constraint circle_con formula: x^2 + y^2 = 1
define facet attribute form_factors real[3]
set_ff := {
foreach facet ff do
{ ff.form_factors[1] := ff.edge[1].length^2;
ff.form_factors[2] := -(ff.edge[1].x*ff.edge[3].x
+ ff.edge[1].y*ff.edge[3].y);
ff.form_factors[3] := ff.edge[3].length^2;
}
}
// Mapping to triangle. Especially nice since can use the three conformal
// degrees of freedom to map particular vertices to corners, and straight
// sides should let Hessian minimize Dirichlet energy in one step.
define cornerx real[4];
cornerx[1] := 1.0;
cornerx[2] := 0.0;
cornerx[3] := -1.0;
cornerx[4] := 1.0;
define cornery real[4];
cornery[1] := 0.0;
cornery[2] := sqrt(3);
cornery[3] := 0.0;
cornery[4] := 0.0;
define constraint side_1_con formula: sqrt(3)*x + y = sqrt(3);
define constraint side_2_con formula: -sqrt(3)*x + y = sqrt(3);
define constraint side_3_con formula: y = 0;
define cornerv integer[3]
cornerv[1] := 0
cornerv[2] := 0
cornerv[3] := 0
define sidecounts integer[3] // how many sides mapped to each triangle side
to_triangle := {
// Check simple connectivity
if vertex_count - edge_count + facet_count != 1 then
{ errprintf "to_disk error: Surface not simply connected. Aborting.\n";
return;
};
set_ff; // set form factors
set facet tension 0;
// Go around outside edges, mapping to unit circle
unfix vertices;
if ( valid_element(vertex[cornerv[1]]) and
(sum(vertex[cornerv[1]].edge,valence==1) == 2) and
valid_element(vertex[cornerv[2]]) and
(sum(vertex[cornerv[2]].edge,valence==1) == 2) and
valid_element(vertex[cornerv[3]]) and
(sum(vertex[cornerv[3]].edge,valence==1) == 2) ) then
{ foreach vertex[cornerv[1]].edge where valence == 1 do
{ thise := oid;
break;
};
starte := thise;
counter := 0;
sidenumber := 1;
do
{ foreach edge[thise].vertex[2].edge eee where valence == 1 and
eee.id != thise do
{ nexte := eee.oid; break; };
thise := nexte;
counter += 1;
if ( (edge[thise].vertex[1].id == cornerv[1]) or
(edge[thise].vertex[1].id == cornerv[2]) or
(edge[thise].vertex[1].id == cornerv[3]) ) then
{ sidecounts[sidenumber] := counter;
counter := 0;
sidenumber += 1;
};
} while thise != starte;
}
else
{ printf "Legal corner vertices not given, so doing my own.\n";
rimcount := sum(edge,valence==1);
sidecounts[1] := rimcount idiv 3;
sidecounts[2] := rimcount idiv 3;
sidecounts[3] := rimcount - sidecounts[1] - sidecounts[2];
foreach edge ee where valence == 1 do { starte := ee.id; break; };
};
// Now go around moving vertices to triangle sides
thise := starte;
for ( sidenum := 1 ; sidenum <= 3; sidenum += 1 )
{
for ( counter := 1; counter <= sidecounts[sidenum] ; counter += 1 )
{ lambda := counter/sidecounts[sidenum];
edge[thise].vertex[1].x := (1-lambda)*cornerx[sidenum]
+ lambda*cornerx[sidenum+1];
edge[thise].vertex[1].y := (1-lambda)*cornery[sidenum]
+ lambda*cornery[sidenum+1];
if ( space_dimension > 2) then
edge[thise].vertex[1].x[3] := 0;
if sidenum == 1 then
set edge[thise].vertex[1] constraint side_1_con;
if sidenum == 2 then
set edge[thise].vertex[1] constraint side_2_con;
if sidenum == 3 then
set edge[thise].vertex[1] constraint side_3_con;
foreach edge[thise].vertex[2].edge eee where valence == 1 and
eee.id != thise do
{ nexte := eee.oid; break; };
thise := nexte;
};
};
// Big move with rim fixed, since movable rim can have negative
// eigenvalues.
fix vertex where on_constraint circle_con;
hessian;
unfix vertex;
}
to_disk := {
// Check simple connectivity
if vertex_count - edge_count + facet_count != 1 then
{ errprintf "to_disk error: Surface not simply connected. Aborting.\n";
return;
};
set_ff; // set form factors
set facet tension 0;
// Go around outside edges, mapping to unit circle
unfix vertices;
rimcount := sum(edge,valence==1);
foreach edge ee where valence == 1 do { starte := ee.id; break; };
thise := starte;
counter := 0;
do
{
edge[thise].vertex[1].x := cos(counter/rimcount*2*pi);
edge[thise].vertex[1].y := sin(counter/rimcount*2*pi);
if ( space_dimension > 2) then
edge[thise].vertex[1].x[3] := 0;
set edge[thise].vertex[1] constraint circle_con;
foreach edge[thise].vertex[2].edge eee where valence == 1 and
eee.id != thise do
{ nexte := eee.oid; break; };
thise := nexte;
counter += 1;
} while thise != starte;
// Big move with rim fixed, since movable rim can have negative
// eigenvalues.
fix vertex where on_constraint circle_con;
hessian;
unfix vertex;
}
// Prerequisites: Dirichlet energy defined, but no others.
// Usage: Remove all constraints and boundaries. Run to_disk. Then evolve.
evolver-2.30c.dfsg/fe/off.cmd 0000755 0001753 0001753 00000000735 11410765113 016267 0 ustar hazelsct hazelsct // off.cmd
// Surface Evolver command to print OFF format file.
// usage:
// do_off >>> "filename.off"
// Programmer: Ken Brakke, brakke@susqu.edu, http://www.susqu.edu/brakke
do_off := {
// file header
printf "OFF\n%g %g %g\n",vertex_count,facet_count,edge_count;
// vertex list
foreach vertex do { printf "%f %f %f \n",x,y,z };
// triangle list
foreach facet ff do
{ printf "3 ";
foreach ff.vertex do printf "%g ",id-1; printf "\n";
}
}
evolver-2.30c.dfsg/fe/twointor.fe 0000644 0001753 0001753 00000002640 11410765113 017223 0 ustar hazelsct hazelsct // twointor.fe
// Two Kelvin tetrakaidecahedra in a torus.
TORUS_FILLED
periods
1.000000 0.000000 0.000000
0.000000 1.000000 0.000000
0.000000 0.000000 1.000000
vertices
1 0.50 0.00 0.75
2 0.25 0.00 0.50
3 0.00 0.25 0.50
4 0.75 0.00 0.50
5 0.00 0.50 0.75
6 0.50 0.00 0.25
7 0.00 0.75 0.50
8 0.50 0.25 0.00
9 0.25 0.50 0.00
10 0.00 0.50 0.25
11 0.50 0.75 0.00
12 0.75 0.50 0.00
edges /* with torus wrap symbols */
1 1 2 * * *
2 2 3 * * *
3 1 4 * * *
4 3 5 * * *
5 2 6 * * *
6 2 7 * - *
7 1 8 * * +
8 4 6 * * *
9 5 9 * * +
10 3 10 * * *
11 3 4 - * *
12 6 8 * * *
13 6 11 * - *
14 7 4 - + *
15 8 12 * * *
16 9 8 * * *
17 9 11 * * *
18 10 7 * * *
19 11 1 * + -
20 12 5 + * -
21 5 7 * * *
22 11 12 * * *
23 10 12 - * *
24 9 10 * * *
faces
1 1 2 4 9 16 -7
2 -2 5 12 -16 24 -10
3 -4 10 18 -21
4 7 15 20 -4 11 -3
5 -1 3 8 -5
6 6 14 -11 -2
7 5 13 -17 24 18 -6
8 -12 13 19 7
9 -16 17 22 -15
10 -10 11 8 12 15 -23
11 -21 9 17 19 1 6
12 -14 -18 23 -22 -13 -8
13 -24 -9 -20 -23
14 -19 22 20 21 14 -3
bodies
1 -1 -2 -3 -4 -5 9 7 11 -9 10 12 5 14 3 volume 0.500
2 2 -6 -7 8 -10 -12 -11 -13 1 13 -14 6 4 -8 volume 0.500
read
// Typical evolution
gogo := { g 5; r; g 5; hessian; r; g 5; hessian; hessian; }
evolver-2.30c.dfsg/fe/orderdmp.cmd 0000755 0001753 0001753 00000002352 11410765113 017326 0 ustar hazelsct hazelsct // orderdmp.cmd
// Evolver command to number string vertices consecutively
// by means of extra attribute 'number',
// and create an ordered dump file.
// Pipe output to file to save it.
// Programmer: Ken Brakke, brakke@susqu.edu, http://www.susqu.edu/brakke
// Usage: oderdmp
define vertex attribute number integer
orderdmp := {
local e_id,newv_id,ecount,first_e,v_id,newe_id;
list topinfo;
ecount := 0; // for safety
// get starting edge, since can't assume edge[1] exists
foreach edge do e_id := id;
first_e := e_id;
v_id := edge[e_id].vertex[1].id;
// follow connected edges
printf "\nVertices\n";
do
{ set vertex[v_id] number ecount+1;
printf "%g %g %g %g\n",ecount+1,vertex[v_id].x,vertex[v_id].y,
vertex[v_id].z;
foreach edge[e_id].vertex vv do
{ if ( vv.id != v_id ) then
{ newv_id := vv.id;
foreach vv.edge ee do
if ee.id != e_id then newe_id := ee.id
}
};
e_id := newe_id; v_id := newv_id;
ecount := ecount + 1;
} while ( (e_id != first_e) and (ecount <= edge_count) );
printf "\nEdges\n";
foreach edge ee do
{
printf"%g %g %g \n",ee.id,ee.vertex[1].number,ee.vertex[2].number;
};
list bottominfo;
}
evolver-2.30c.dfsg/src/ 0000755 0001753 0001753 00000000000 11410765113 015215 5 ustar hazelsct hazelsct evolver-2.30c.dfsg/src/popfilm.c 0000644 0001753 0001753 00000513411 11410765113 017034 0 ustar hazelsct hazelsct /*************************************************************
* This file is part of the Surface Evolver source code. *
* Programmer: Ken Brakke, brakke@susqu.edu *
*************************************************************/
/******************************************************************
*
* File: popfilm.c
*
* Purpose: Convert all tangent cones to minimal cones in
* soapfilm model.
*/
#include "include.h"
/*********************************************************************
*
* Function: popfilm()
*
* Purpose: Overall control of tangent cone minimization.
* Creates sorted list of vertex-facet incidences
* sorted on vertex. Analyzes tangent cone for each
* vertex and calls minimizer for the non-minimal.
*/
/* comparison routine for qsort */
static int vfcomp(a,b)
struct verfacet *a,*b;
{
if ( a->v_id < b->v_id ) return -1;
if ( a->v_id > b->v_id ) return 1;
return 0;
}
int popfilm()
{
int popped = 0;
if ( web.counts_reported & edge_pop_count_bit )
web.edge_pop_count = 0;
popped = edgepop_film();
web.counts_reported |= edge_pop_count_bit;
sprintf(msg,"Edges popped: %d\n",popped); outstring(msg);
popped = verpop_film();
return popped;
}
/********************************************************************
*
* Function: edgepop_film()
*
* Purpose: Reconfigure all edges with more than 3 facets into
* triple edges. Also does two or more facets with
* common edge on boundary or constraint.
*/
int edgepop_film()
{
edge_id e_id,sentinel;
int popped = 0;
/* Loop through all edges, popping as you go. New edges created
during popping will be scanned to see if they are still
pop-worthy.
*/
e_id = NULLEDGE;
while ( generate_all(EDGE,&e_id,&sentinel) )
{ popped += pop_one_edge(e_id);
}
return popped;
}
/***************************************************************************
*
* function: vertex_degfree()
*
* purpose: find degrees of freedom left by a vertex's constraints
*
*/
int vertex_degfree(v_id)
vertex_id v_id;
{ int degfree;
int vattr = get_vattr(v_id);
struct boundary *vbdry;
conmap_t *vmap;
int i;
/* Get degrees of freedom of vertex */
degfree = SDIM;
if ( vattr & FIXED ) degfree = 0;
else if ( vattr & BOUNDARY )
{ vbdry = get_boundary(v_id);
if ( (vbdry->attr & NONWALL) )
degfree = vbdry->pcount;
}
else if ( vattr & CONSTRAINT )
{ vmap = get_e_constraint_map(v_id);
for ( i = 1; i <= (int)vmap[0] ; i++ )
if (!((get_constraint(vmap[i])->attr)&(NONPOSITIVE|NONNEGATIVE|NONWALL)))
degfree--;
}
return degfree;
}
/***************************************************************************
*
* function: edge_degfree()
*
* purpose: find degrees of freedom left by a edge's constraints
*
*/
int edge_degfree(e_id)
edge_id e_id;
{ int degfree;
int eattr = get_eattr(e_id);
struct boundary *ebdry;
conmap_t *emap;
int i;
/* Get degrees of freedom of edge */
degfree = SDIM;
if ( eattr & FIXED ) degfree = 0;
else if ( eattr & BOUNDARY )
{ ebdry = get_edge_boundary(e_id);
if ( (ebdry->attr & NONWALL) )
degfree = ebdry->pcount;
}
else if ( eattr & CONSTRAINT )
{ emap = get_e_constraint_map(e_id);
for ( i = 1; i <= (int)emap[0] ; i++ )
if (!((get_constraint(emap[i])->attr)&(NONPOSITIVE|NONNEGATIVE|NONWALL)))
degfree--;
}
return degfree;
}
/***************************************************************************
*
* function: facet_degfree()
*
* purpose: find degrees of freedom left by a facet's constraints
*
*/
int facet_degfree(f_id)
facet_id f_id;
{ int degfree;
int fattr = get_fattr(f_id);
struct boundary *fbdry;
conmap_t *fmap;
int i;
/* Get degrees of freedom of edge */
degfree = SDIM;
if ( fattr & FIXED ) degfree = 0;
else if ( fattr & BOUNDARY )
{ fbdry = get_facet_boundary(f_id);
if ( (fbdry->attr & NONWALL) )
degfree = fbdry->pcount;
}
else if ( fattr & CONSTRAINT )
{ fmap = get_f_constraint_map(f_id);
for ( i = 1; i <= (int)fmap[0] ; i++ )
if (!((get_constraint(fmap[i])->attr)&(NONPOSITIVE|NONNEGATIVE|NONWALL)))
degfree--;
}
return degfree;
}
/********************************************************************
*
* Function: pop_one_edge()
*
* Purpose: Try popping one edge. Tests for more than 3 facets.
* Also does two or more facets with
* common edge on boundary or constraint.
*/
REAL new_displacement[MAXCOORD]; /* one normal of splittin wedge */
int pop_one_edge(e_id)
edge_id e_id;
{
int facet_count = 0;
facetedge_id fe_id,fe,key_fe=NULLID,new_key;
REAL side[MAXCOORD],sideA[MAXCOORD],sideB[MAXCOORD];
REAL normA,normB,normalA[MAXCOORD],normalB[MAXCOORD];
REAL maxcos,newcos;
int didsplit;
int foundwedge;
facetedge_id first_fe;
int eattr = get_eattr(e_id);
facet_id f1,f2;
int attr1,attr2;
int i,k;
REAL midnormal[MAXCOORD];
int popped = 0;
int degfree; /* degrees of freedom of edge */
int fdegfree,next_fdegfree;
int popattr = -1; /* in case of kraynikpop */
int kraynikwedge; /* whether current wedge has kraynik preference */
int foundkraynik;
int maxffree; /* maximum degrees of freedom of adjacent facets */
int maxffreen; /* number of adjacent facets with that freedom */
int septum_flag=1; /* whether to put in septum joining popped edges */
/* count facets around edge */
fe_id = first_fe = get_edge_fe(e_id);
maxffree = 0; maxffreen = 0;
if ( valid_id(fe_id) )
do
{ int ffree = facet_degfree(get_fe_facet(fe_id));
if ( ffree > maxffree )
{ maxffree = ffree; maxffreen = 1; }
else if ( ffree == maxffree ) maxffreen ++;
facet_count++;
fe_id = get_next_facet(fe_id);
} while ( valid_id(fe_id) && !equal_id(fe_id,first_fe) );
/* only pop if more than 3 facets, or a wall or wire */
if ( !(eattr & (FIXED|BOUNDARY|CONSTRAINT) && (maxffreen >= 2))
&& !(maxffreen > 3) )
return 0;
/* Get degrees of freedom of edge */
degfree = edge_degfree(e_id);
if ( (facet_count == 3) && (degfree == SDIM) ) return 0;
if ( kraynikpopedge_flag )
{ /* find facets that disagree on edge_pop_attribute */
popattr = find_attribute(FACET,"edge_pop_attribute");
}
foundwedge = 0;
foundkraynik = 0;
if ( pop_disjoin_flag && (facet_count == 4) )
{ /* test for merging Plateau borders */
facetedge_id fea,feb,fec,fed;
body_id ba,bb,bc,bd;
fea = get_edge_fe(e_id);
feb = get_next_facet(fea);
fec = get_next_facet(feb);
fed = get_next_facet(fec);
ba = get_facet_body(get_fe_facet(fea));
bb = get_facet_body(get_fe_facet(feb));
bc = get_facet_body(get_fe_facet(fec));
bd = get_facet_body(get_fe_facet(fed));
if ( valid_id(ba) && equal_id(ba,bc) )
{ key_fe = feb;
foundwedge = 1;
septum_flag = 0;
}
else if ( valid_id(bb) && equal_id(bb,bd) )
{ key_fe = fea;
foundwedge = 1;
septum_flag = 0;
}
}
if ( !foundwedge )
{
/* find narrowest wedge to pull out */
get_edge_side(e_id,side);
maxcos = -2.0; /* for finding minimum angle between facets */
/* find first facet normal */
fe = get_edge_fe(e_id);
get_fe_side(get_next_edge(fe),sideA);
cross_prod(side,sideA,normalA);
normA = sqrt(SDIM_dot(normalA,normalA));
next_fdegfree = fdegfree = facet_degfree(get_fe_facet(fe));
for ( i = 0 ; i < facet_count ; i++ )
{ facetedge_id next_fe;
next_fe = get_next_facet(fe);
fdegfree = next_fdegfree;
next_fdegfree = facet_degfree(get_fe_facet(next_fe));
/* test wedge for compatibility */
if ( fdegfree < 3 ) continue;
if ( next_fdegfree < 3 ) continue;
f1 = get_fe_facet(fe);
f2 = get_fe_facet(next_fe);
attr1 = get_fattr(f1);
attr2 = get_fattr(f2);
if ( get_facet_boundary(f1) != get_facet_boundary(f2) )
continue;
if ( (attr1 & CONSTRAINT) || (attr2 & CONSTRAINT) )
{ conmap_t *map1 = get_f_constraint_map(f1);
conmap_t *map2 = get_f_constraint_map(f2);
conmap_t ii,jj,found;
found = 0;
for ( ii = 1 ; ii <= map1[0] ; ii++ )
{ for ( jj = 1; jj <= map2[0] ; jj++ )
if ( map1[ii] == map2[jj] ) found++;
}
if ( (found != map1[0]) || ( found != map2[0]) )
continue;
}
if ( (facet_count <= 3) &&
((fdegfree <= degfree)||(next_fdegfree <= degfree) ) )
continue; /* fake wall */
/* get normal */
get_fe_side(get_next_edge(next_fe),sideB);
cross_prod(side,sideB,normalB);
normB = sqrt(SDIM_dot(normalB,normalB));
newcos = SDIM_dot(normalA,normalB)/normA/normB;
/* If phases in effect, can estimate force */
if ( phase_flag )
{ REAL tensionA = get_facet_density(f1);
REAL tensionB = get_facet_density(f2);
REAL tensionC; /* for the proposed interface */
REAL force1;
REAL sum;
int ii = get_b_phase(get_facet_body(f1));
int jj = get_b_phase(get_facet_body(inverse_id(f2)));
tensionC = phase_data[ii][jj];
for ( k = 0, sum = 0.0 ; k < SDIM ; k++ )
{ REAL term =
(tensionA*normalA[0]/normA + tensionB*normalB[0]/normB);
sum += term;
}
force1 = sqrt(sum);
newcos = force1 - tensionC;
}
if ( popattr >= 0 ) /* kraynikpop test */
{ kraynikwedge = ( *(int*)get_extra(f1,popattr) !=
*(int*)get_extra(f2,popattr) );
}
else kraynikwedge = 0;
if ( ((newcos > maxcos) && (kraynikwedge >= foundkraynik))
|| (kraynikwedge > foundkraynik) )
{ key_fe = next_fe;
maxcos = newcos;
for ( k = 0 ; k < SDIM ; k++ )
midnormal[k] = normalA[k]/normA + normalB[k]/normB;
cross_prod(midnormal,side,new_displacement);
}
if ( kraynikwedge ) foundkraynik = 1;
/* set up for next angle */
normA = normB;
memcpy((char *)normalA,(char *)normalB,sizeof(normalA));
fe = next_fe;
}
/* now a little check just to make sure things happened as planned */
if ( (facet_count >= 4) && (maxcos < 0.0) && !foundkraynik )
{ sprintf(errmsg,
"Can't find poppable pair of facets on poppable edge %s.\n",
ELNAME(e_id));
kb_error(1299,errmsg, RECOVERABLE);
}
}
if ( !valid_id(key_fe) ) return 0;
/* check boundary and constraint compatibility of wedge */
/* test to see if we really want to do this pop */
f1 = get_fe_facet(key_fe);
f2 = get_fe_facet(get_next_edge(key_fe));
attr1 = get_fattr(f1);
attr2 = get_fattr(f2);
if ( (attr1 & FIXED) || (attr2 & FIXED) )
return 0;
if ( get_facet_boundary(f1) != get_facet_boundary(f2) )
return 0;
if ( (attr1 & CONSTRAINT) || (attr2 & CONSTRAINT) )
{ conmap_t *map1 = get_e_constraint_map(f1);
conmap_t *map2 = get_e_constraint_map(f2);
conmap_t ii,jj,found;
found = 0;
for ( ii = 1 ; ii <= map1[0] ; ii++ )
{
for ( jj = 1; jj <= map2[0] ; jj++ )
if ( map1[ii] == map2[jj] ) found++;
}
if ( (found != map1[0]) || ( found != map2[0]) )
return 0;
}
if ( verbose_flag )
{ sprintf(msg,"Popping edge %s\n",ELNAME(e_id));
outstring(msg);
}
didsplit = 0;
if ( (facet_count == 2) && (degfree==2) )
{ /* special treatment, since may split either way */
popped = two_split(key_fe,septum_flag);
if ( popped ) return popped; /* else do Y pull-out */
}
/* try propagating split forward */
new_key = key_fe;
while ( try_prop(&new_key,key_fe,septum_flag) )
{ didsplit = 1;
if ( verbose_flag )
{ sprintf(msg," Propagating pop to edge %s\n",ELNAME(get_fe_edge(new_key)));
outstring(msg);
}
popped++;
}
/* try propagating split backward */
new_key = inverse_id(get_prev_facet(key_fe));
while ( try_prop(&new_key,inverse_id(get_prev_facet(key_fe)),septum_flag) )
{ didsplit = 1;
if ( verbose_flag )
{ sprintf(msg," Propagating pop to edge %s\n",ELNAME(get_fe_edge(key_fe)));
outstring(msg);
}
popped++;
}
/* if can't split forward or backward, divide edge and split */
if ( !didsplit )
{
edge_refine(e_id);
popped += pop_one_edge(e_id); /* try again */
}
return popped;
} /* end pop_one_edge */
/***********************************************************************
*
* Function: try_prop()
*
* Purpose: Sees if vertex at head of *pass_key can be split.
* If it can, it does. If split can be propagated
* further, it returns the next edge to try in *pass_key.
* If the vertex was split, it returns 1, else 0.
* Does not split FIXED vertices. Or BOUNDARY vertices.
*/
int try_prop(pass_key,start_key,septum_flag)
facetedge_id *pass_key;
facetedge_id start_key; /* to check for complete loop */
int septum_flag; /* whether to put septum between popped edges */
{
int splitflag;
int propflag;
facetedge_id wing_fe;
facetedge_id flip_fe;
facetedge_id new_key=0;
facetedge_id key_fe = *pass_key;
edge_id e_id = get_fe_edge(key_fe);
edge_id next_e=0;
if ( !valid_id(*pass_key) ) return 0;
/* if ( get_vattr(get_fe_headv(key_fe)) & FIXED ) return 0; */
/* don't even try if valence is already <= 3 */
/*if ( get_edge_valence(e_id) <= 3 ) return 0; */
/* swing forward on one side until find multiple edge */
flip_fe = inverse_id(key_fe);
for (;;)
{
wing_fe = get_next_edge(inverse_id(flip_fe));
if ( equal_id(wing_fe,start_key) )
{ /* have made complete loop around */
splitflag = 1;
propflag = 0;
break;
}
flip_fe = get_next_facet(wing_fe);
if ( equal_id(wing_fe,flip_fe) )
{ /* dead end on wing, so OK to split vertex maybe */
if ( edge_degfree(get_fe_edge(wing_fe)) >= 2 )
splitflag = 1;
else splitflag = 0;
propflag = 0;
break;
}
if ( !equal_id(wing_fe,get_next_facet(flip_fe))
|| (get_eattr(get_fe_edge(wing_fe)) & (FIXED|BOUNDARY|CONSTRAINT)) )
{ /* have found multiple edge, or wall or wire */
next_e = get_fe_edge(wing_fe);
if ( !equal_element(e_id,next_e) )
{ /* have found legitimate next edge */
splitflag = 1;
propflag = 1;
new_key = wing_fe;
break;
}
if ( equal_element(wing_fe,get_prev_facet(key_fe)) )
{ /* have cirque, so OK to split, but no propagation */
splitflag = 1;
propflag = 0;
}
else
{ /* have cirque crossing proposed split */
/* which ends propagation */
splitflag = 0;
propflag = 0;
}
break;
}
}
if ( !splitflag ) return 0;
/* swing forward on other side until find multiple edge */
flip_fe = inverse_id(get_prev_facet(key_fe));
for (;;)
{
wing_fe = get_next_edge(inverse_id(flip_fe));
flip_fe = get_next_facet(wing_fe);
if ( equal_id(wing_fe,flip_fe) )
{ /* dead end on wing, so OK to split vertex maybe */
if ( edge_degfree(get_fe_edge(wing_fe)) < 2 )
splitflag = 0;
propflag = 0;
break;
}
if ( !equal_id(wing_fe,get_next_facet(flip_fe))
|| (get_eattr(get_fe_edge(wing_fe)) & (FIXED|BOUNDARY|CONSTRAINT)) )
{ /* have found multiple edge */
if ( !equal_id(get_fe_edge(wing_fe),next_e) )
{
/* can't split; have serious nonminimal vertex */
splitflag = 0;
propflag = 0;
break;
}
else /* check normals */
{
}
break;
}
}
if ( !propflag ) new_key = NULLFACETEDGE;
/* check to see if new_key is already just triple */
{ facetedge_id feb = get_next_facet(new_key);
facetedge_id fec = get_next_facet(feb);
facetedge_id fed = get_next_facet(fec);
if ( equal_id(fec,new_key) )
{ /* can't split further */
splitflag = 0;
}
else if ( equal_id(fed,new_key) )
{ /* already triple edge; split and stop */
propflag = 0;
}
}
if ( splitflag ) versplit(key_fe,new_key,septum_flag);
if ( !propflag ) new_key = NULLFACETEDGE;
*pass_key = new_key;
return splitflag;
} /* end try_prop */
/**********************************************************************
*
* Function: versplit()
*
* Purpose: Split a wedge of facets off a vertex along two edges.
* Old edges go with split wedge (old edges now proper
* minimal cones) and new edges have rest of old facets
* and await scanning for minimality. Arguments are
* facetedges for the two edges inside the wedge; if
* second is null, means there is no second edge.
* This is essentially the reverse of eliminating an edge.
*/
void versplit(fe_a,fe_b,septum_flag)
facetedge_id fe_a,fe_b;
int septum_flag;
{
vertex_id old_v = get_fe_headv(fe_a);
vertex_id new_v;
edge_id new_e=0,new_a=0,new_b=0,e_id;
edge_id old_a = get_fe_edge(fe_a);
edge_id old_b = get_fe_edge(fe_b);
facetedge_id fe_aa = get_prev_facet(fe_a);
facetedge_id fe_bb = get_prev_facet(fe_b);
facetedge_id fe_a_old,fe_a_new,fe_a_e;
facetedge_id fe_b_old=0,fe_b_new=0,fe_b_e=0;
facet_id new_fa,new_fb=0;
body_id b_id;
int i;
REAL *x;
int halfflag;
facetedge_id fe,first_fe;
int valence = get_edge_valence(old_a);
conmap_t *vmap,*emap,*fmap;
facetedge_id halffe;
/* create a new vertex, which will be split away with wedge */
new_v = dup_vertex(old_v);
x = get_coord(new_v);
for ( i = 0 ; i < SDIM ; i++ )
x[i] += 0.01*new_displacement[i];
if ( septum_flag )
{ /* create new edge between vertices */
new_e = new_edge(old_v,new_v,NULLID);
}
/* create new edges split off from wedge */
if ( !equal_id(get_prev_facet(fe_aa),fe_a) )
{
new_a = dup_edge(old_a);
insert_vertex_edge(get_edge_tailv(old_a),new_a);
insert_vertex_edge(old_v,inverse_id(new_a));
}
/* fix up attributes of old edge, in case pulling off wall */
unset_attr(old_a,FIXED);
set_edge_boundary_num(old_a,0);
unset_attr(old_a,BOUNDARY);
fmap = get_f_constraint_map(get_fe_facet(fe_a));
emap = get_e_constraint_map(old_a);
for ( i = 1 ; i <= (int)fmap[0] ; i++ )
emap[i] = fmap[i];
for ( ; i <= (int)emap[0] ; i++ ) emap[i] = 0;
emap[0] = fmap[0];
if ( emap[0] == 0 ) unset_attr(old_a,CONSTRAINT);
else set_attr(old_a,CONSTRAINT);
if ( valid_id(fe_b) )
{
new_b = dup_edge(old_b);
insert_vertex_edge(old_v,new_b);
insert_vertex_edge(get_edge_headv(old_b),inverse_id(new_b));
/* fix up attributes of old edge, in case pulling off wall */
unset_attr(old_b,FIXED);
set_edge_boundary_num(old_b,0);
unset_attr(old_b,BOUNDARY);
fmap = get_f_constraint_map(get_fe_facet(fe_b));
emap = get_e_constraint_map(old_b);
for ( i = 1 ; i <= (int)fmap[0] ; i++ )
emap[i] = fmap[i];
for ( ; i <= (int)emap[0] ; i++ ) emap[i] = 0;
emap[0] = fmap[0];
if ( emap[0] == 0 ) unset_attr(old_b,CONSTRAINT);
else set_attr(old_b,CONSTRAINT);
}
/* reset edge endpoints coming into new_v */
fe = fe_a;
halfflag = 0;
halffe = NULLID; /* for attributes of new_v */
do
{ e_id = get_fe_edge(fe);
remove_vertex_edge(old_v,inverse_id(e_id));
set_edge_headv(e_id,new_v);
if ( equal_id(fe,get_next_facet(fe)) )
{ halfflag = 1; /* need to go back and do other side of wedge */
halffe = fe;
break;
}
fe = get_next_facet(inverse_id(get_next_edge(fe)));
if ( !valid_id(halffe) ) halffe = fe;
} while ( !equal_id(fe,fe_a) );
if ( halfflag )
{ fe = get_prev_facet(inverse_id(get_next_edge(fe_aa)));
if ( !valid_id(halffe) ) halffe = fe;
do
{
e_id = get_fe_edge(fe);
remove_vertex_edge(old_v,inverse_id(e_id));
set_edge_headv(e_id,new_v);
if ( equal_id(fe,get_next_facet(fe)) )
break;
fe = get_prev_facet(inverse_id(get_next_edge(fe)));
} while ( !equal_id(fe,fe_aa) );
}
/* fix up attributes of new_v, which was clone of old_v */
unset_attr(new_v,FIXED);
if ( valid_id(halffe) )
{ /* set attributes to same as halffe */
e_id = get_fe_edge(halffe);
if ( get_eattr(e_id) & BOUNDARY )
{ if ( get_boundary(new_v) != get_edge_boundary(e_id) )
kb_error(2440,"Trying to pop vertex not on same boundary as incoming edge.",RECOVERABLE);
}
else
{ set_boundary_num(new_v,0);
unset_attr(new_v,BOUNDARY);
}
vmap = get_v_constraint_map(new_v);
emap = get_e_constraint_map(e_id);
for ( i = 1 ; i <= (int)emap[0] ; i++ ) vmap[i] = emap[i];
for ( ; i <= (int)vmap[0] ; i++ ) vmap[i] = 0;
vmap[0] = emap[0];
if ( vmap[0] ) set_attr(new_v,CONSTRAINT);
else unset_attr(new_v,CONSTRAINT);
}
if ( septum_flag )
{
/* fix up attributes of new_e, which was brand new */
if ( valid_id(halffe) )
{ /* set attributes to same as halffe */
e_id = get_fe_edge(halffe);
if ( get_eattr(e_id) & BOUNDARY )
{ set_edge_boundary_num(new_e,get_edge_boundary_num(e_id));
set_attr(new_e,BOUNDARY);
}
if ( get_eattr(e_id) & CONSTRAINT )
{ conmap_t *eemap = get_e_constraint_map(new_e);
emap = get_e_constraint_map(e_id);
for ( i = 1 ; i <= (int)emap[0] ; i++ ) eemap[i] = emap[i];
eemap[0] = emap[0];
set_attr(new_e,CONSTRAINT);
}
}
/* create two new facets */
new_fa = dup_facet(get_fe_facet(fe_a));
if ( valid_id(fe_b) )
{
new_fb = dup_facet(get_fe_facet(fe_b));
}
/* create new facet-edges */
fe_a_e = new_facetedge(new_fa,new_e);
fe_a_new = new_facetedge(new_fa,new_a);
fe_a_old = new_facetedge(new_fa,inverse_id(old_a));
if ( valid_id(fe_b) )
{
fe_b_e = new_facetedge(new_fb,inverse_id(new_e));
fe_b_new = new_facetedge(new_fb,new_b);
fe_b_old = new_facetedge(new_fb,inverse_id(old_b));
}
/* link elements to facet-edges */
set_edge_fe(old_a,inverse_id(fe_a_old));
set_edge_fe(new_a,fe_a_new);
set_edge_fe(new_e,fe_a_e);
set_facet_fe(new_fa,fe_a_new);
if ( valid_id(fe_b) )
{
set_edge_fe(old_b,inverse_id(fe_b_old));
set_edge_fe(new_b,fe_b_new);
set_facet_fe(new_fb,fe_b_new);
}
/* link edges around new facets */
set_next_edge(fe_a_e,fe_a_old);
set_next_edge(fe_a_old,fe_a_new);
set_next_edge(fe_a_new,fe_a_e);
set_prev_edge(fe_a_old,fe_a_e);
set_prev_edge(fe_a_new,fe_a_old);
set_prev_edge(fe_a_e,fe_a_new);
if ( valid_id(fe_b) )
{
set_next_edge(fe_b_e,fe_b_new);
set_next_edge(fe_b_old,fe_b_e);
set_next_edge(fe_b_new,fe_b_old);
set_prev_edge(fe_b_old,fe_b_new);
set_prev_edge(fe_b_new,fe_b_e);
set_prev_edge(fe_b_e,fe_b_old);
}
/* link facets around edges */
/* new middle edge */
if ( valid_id(fe_b) )
{ set_next_facet(fe_a_e,inverse_id(fe_b_e));
set_next_facet(fe_b_e,inverse_id(fe_a_e));
set_prev_facet(fe_a_e,inverse_id(fe_b_e));
set_prev_facet(fe_b_e,inverse_id(fe_a_e));
}
else
{ set_next_facet(fe_a_e,fe_a_e);
set_prev_facet(fe_a_e,fe_a_e);
}
/* facet A old edge */
set_next_facet(fe_a_old,inverse_id(fe_a));
set_prev_facet(fe_a_old,inverse_id(fe_aa));
/* facet A new edge */
if ( valence >= 3 )
{ set_next_facet(fe_a_new,get_next_facet(fe_a));
set_prev_facet(fe_a_new,get_prev_facet(fe_aa));
}
else
{ set_next_facet(fe_a_new,fe_a_new);
set_prev_facet(fe_a_new,fe_a_new);
}
/* reset old links */
set_next_facet(get_prev_facet(fe_a_old),fe_a_old);
set_prev_facet(get_next_facet(fe_a_old),fe_a_old);
set_next_facet(get_prev_facet(fe_a_new),fe_a_new);
set_prev_facet(get_next_facet(fe_a_new),fe_a_new);
/* reset edges of facet-edges around new edge */
fe = first_fe = get_edge_fe(new_a);
if ( valid_id(fe) ) do
{ set_fe_edge(fe,new_a);
fe = get_next_facet(fe);
} while ( valid_id(fe) && !equal_id(fe,first_fe) );
if ( valid_id(fe_b) )
{ /* facet B old edge */
set_next_facet(fe_b_old,inverse_id(fe_b));
set_prev_facet(fe_b_old,inverse_id(fe_bb));
/* facet B new edge */
set_next_facet(fe_b_new,get_next_facet(fe_b));
set_prev_facet(fe_b_new,get_prev_facet(fe_bb));
/* reset old links */
set_next_facet(get_prev_facet(fe_b_old),fe_b_old);
set_prev_facet(get_next_facet(fe_b_old),fe_b_old);
set_next_facet(get_prev_facet(fe_b_new),fe_b_new);
set_prev_facet(get_next_facet(fe_b_new),fe_b_new);
/* reset edges of facet-edges around new edge */
fe = first_fe = get_edge_fe(new_b);
if ( valid_id(fe) ) do
{ set_fe_edge(fe,new_b);
fe = get_next_facet(fe);
} while ( valid_id(fe) && !equal_id(fe,first_fe) );
}
/* set new facet bodies */
fe = get_next_facet(fe_a_new);
b_id = get_facet_body(get_fe_facet(fe));
set_facet_body(inverse_id(new_fa),b_id);
if ( valid_id(fe_b) )
set_facet_body(inverse_id(new_fb),b_id);
fe = inverse_id(get_prev_facet(fe_a_new));
b_id = get_facet_body(get_fe_facet(fe));
set_facet_body(new_fa,b_id);
if ( valid_id(fe_b) )
set_facet_body(new_fb,b_id);
/* Tension, if phases */
if ( phase_flag )
{ set_f_phase_density(new_fa);
if ( valid_id(fe_b) )
set_f_phase_density(new_fb);
}
/* set velocity, so can tell edge is supposed to grow */
{ REAL *velocity;
velocity = get_velocity(old_v);
for ( i = 0 ; i < SDIM ; i++ )
velocity[i] = -new_displacement[i];
velocity = get_velocity(new_v);
for ( i = 0 ; i < SDIM ; i++ )
velocity[i] = new_displacement[i];
}
} /* end if septum_flag */
else
{ /* no septum, so just reset facetedge links */
facetedge_id fe_a_next = get_next_facet(fe_a);
facetedge_id fe_aa_prev = get_prev_facet(fe_aa);
if ( !equal_id(fe_a_next,fe_aa) )
{
set_next_facet(fe_a,fe_aa);
set_prev_facet(fe_aa,fe_a);
set_next_facet(fe_aa_prev,fe_a_next);
set_prev_facet(fe_a_next,fe_aa_prev);
set_fe_edge(fe_a_next,new_a);
set_fe_edge(fe_aa_prev,new_a);
set_edge_fe(old_a,fe_a);
set_edge_fe(new_a,fe_a_next);
}
set_edge_headv(old_a,new_v);
if ( valid_id(fe_b) )
{ facetedge_id fe_b_next = get_next_facet(fe_b);
facetedge_id fe_bb_prev = get_prev_facet(fe_bb);
set_next_facet(fe_b,fe_bb);
set_prev_facet(fe_bb,fe_b);
set_next_facet(fe_bb_prev,fe_b_next);
set_prev_facet(fe_b_next,fe_bb_prev);
set_fe_edge(fe_b_next,new_b);
set_fe_edge(fe_bb_prev,new_b);
set_edge_tailv(old_b,new_v);
set_edge_fe(old_b,fe_b);
set_edge_fe(new_b,fe_b_next);
}
}
}
/***************************************************************************
*
* function: two_split()
*
* purpose: Handle special case of two facets meeting at an edge on a wall,
* with two degrees of freedom on the wall so splitting apart
* is legal.
*
* input: facetedge of edge known to have 2 facets and 2 degrees of freedom.
*
* return: Number of edges split.
*/
int two_split(key_fe,septum_flag)
facetedge_id key_fe; /* starting edge */
int septum_flag; /* no septum not implemented yet */
{
facetedge_id headsplitlist[10];
int headsplitcount = 0;
int headsplitflag = 0; /* whether to split end vertex */
facetedge_id tailsplitlist[10];
int tailsplitcount = 0;
int tailsplitflag = 0; /* 7hether to split end vertex */
facetedge_id fe_a,fe_aa,fe_aaa;
int stopflag;
int popped = 0;
int splitcount;
int i;
/* See how far potential split can be traced in each direction,
checking that Y split is not more suitable all the way.
*/
/* Try forward */
fe_a = key_fe;
headsplitflag = 1;
for (stopflag=0;!stopflag;)
{ int head_degfree;
int aa_degfree;
headsplitlist[headsplitcount++] = fe_a;
/* test head vertex */
head_degfree = vertex_degfree(get_fe_headv(fe_a));
if ( head_degfree == 0 )
{ /* can't split */
headsplitflag = 0;
break;
}
/* find next wall edge forward */
fe_aaa = inverse_id(fe_a);
do
{
fe_aa = inverse_id(get_next_edge(fe_aaa));
fe_aaa = get_next_facet(fe_aa);
if ( !equal_id(fe_aa,get_next_facet(fe_aaa)) )
{ /* run into valence more than 2, can't split head */
stopflag = 1;
headsplitflag = 0;
break;
}
if ( equal_id(fe_aa,fe_aaa) )
{ /* valence 1, could still split head */
aa_degfree = edge_degfree(get_fe_edge(fe_aa));
if ( aa_degfree < 2 ) headsplitflag = 0;
else headsplitflag = 1;
stopflag = 1;
break;
}
/* now have valence 2 */
aa_degfree = edge_degfree(get_fe_edge(fe_aa));
if ( aa_degfree == 2 )
{ /* back to wall */
if ( (facet_degfree(get_fe_facet(fe_aa)) != 3)
|| (facet_degfree(get_fe_facet(get_next_facet(fe_aa))) != 3) )
stopflag = 1;
break;
}
else if ( aa_degfree != 3 )
{ /* end of the line */
stopflag = 1;
}
} while ( aa_degfree == 3 );
fe_a = fe_aa;
} /* end of going forward */
/* go backward */
fe_a = inverse_id(key_fe);
tailsplitflag = 1;
for (stopflag=0;!stopflag;)
{ int tail_degfree;
int aa_degfree;
tailsplitlist[tailsplitcount++] = fe_a;
/* test tail vertex */
tail_degfree = vertex_degfree(get_fe_headv(fe_a));
if ( tail_degfree == 0 )
{ /* can't split */
tailsplitflag = 0;
break;
}
/* find next wall edge forward */
fe_aaa = inverse_id(fe_a);
do
{ fe_aa = inverse_id(get_next_edge(fe_aaa));
fe_aaa = get_next_facet(fe_aa);
if ( !equal_id(fe_aa,get_next_facet(fe_aaa)) )
{ /* run into valence more than 2, can't split tail */
stopflag = 1;
tailsplitflag = 0;
break;
}
if ( equal_id(fe_aa,fe_aaa) )
{ /* valence 1, could still split tail */
aa_degfree = edge_degfree(get_fe_edge(fe_aa));
if ( aa_degfree < 2 ) tailsplitflag = 0;
else tailsplitflag = 1;
stopflag = 1;
break;
}
/* now have valence 2 */
aa_degfree = edge_degfree(get_fe_edge(fe_aa));
if ( aa_degfree == 2 )
{ /* back to wall */
if ( (facet_degfree(get_fe_facet(fe_aa)) != 3)
|| (facet_degfree(get_fe_facet(get_next_facet(fe_aa))) != 3) )
stopflag = 1;
break;
}
else if ( aa_degfree != 3 )
{ /* end of the line */
stopflag = 1;
}
} while ( aa_degfree == 3 );
fe_a = fe_aa;
} /* end of going backward */
/* split things */
splitcount = headsplitcount + tailsplitcount - 1;
if ( (splitcount == 1) && !headsplitflag && !tailsplitflag )
return 0;
/* now get into one list for splitting */
for ( i = headsplitcount-1 ; i >= 0 ; i-- )
headsplitlist[i+tailsplitcount-1] = headsplitlist[i];
for ( i = 1 ; i < tailsplitcount ; i++ )
headsplitlist[tailsplitcount-i] = inverse_id(tailsplitlist[i]);
/* Test to see if all edges have their facets less than 90 degrees
apart, in which case we don't split, but let Y pull-out happen.
*/
for ( i = 0 ; i < splitcount ; i++ )
{ facetedge_id fe = headsplitlist[i];
facetedge_id fe_a = get_next_facet(fe);
REAL normal[MAXCOORD];
REAL normala[MAXCOORD];
get_facet_normal(get_fe_facet(fe),normal);
get_facet_normal(get_fe_facet(fe_a),normala);
if ( SDIM_dot(normal,normala) < 0 )
break; /* too wide */
}
if ( i == splitcount ) return 0;
/* split new edge off with facetedges in list */
for ( i = 0 ; i < splitcount ; i++ )
{ facetedge_id fe,fe_b,fe_c;
edge_id new_e,old_e;
fe = headsplitlist[i];
old_e = get_fe_edge(fe);
new_e = dup_edge(old_e);
if ( verbose_flag )
{ sprintf(msg,"Popping valence 2 edge %s on a constraint.\n",ELNAME(old_e));
outstring(msg);
}
insert_vertex_edge(get_edge_tailv(old_e),new_e);
insert_vertex_edge(get_edge_headv(old_e),inverse_id(new_e));
fe_a = get_next_facet(fe);
set_fe_edge(fe,new_e);
set_edge_fe(new_e,fe);
set_edge_fe(old_e,fe_a);
set_next_facet(fe,fe);
set_prev_facet(fe,fe);
set_next_facet(fe_a,fe_a);
set_prev_facet(fe_a,fe_a);
if ( (i > 0) || tailsplitflag )
{ vertex_id old_tail = get_edge_tailv(old_e);
vertex_id new_tail = dup_vertex(old_tail);
fe_b = fe;
fe_c = NULLID;
/* reconnect edges */
for (;;)
{
remove_vertex_edge(old_tail,get_fe_edge(fe_b));
set_edge_tailv(get_fe_edge(fe_b),new_tail);
if ( equal_id(fe_b,fe_c) ) break;
fe_c = inverse_id(get_prev_edge(fe_b));
fe_b = get_next_facet(fe_c);
}
}
if ( (i == splitcount-1) && headsplitflag )
{ vertex_id old_head = get_edge_headv(old_e);
vertex_id new_head = dup_vertex(old_head);
fe_b = fe;
fe_c = NULLID;
/* reconnect edges */
for (;;)
{
remove_vertex_edge(old_head,inverse_id(get_fe_edge(fe_b)));
set_edge_headv(get_fe_edge(fe_b),new_head);
if ( equal_id(fe_b,fe_c) ) break;
fe_c = inverse_id(get_next_edge(fe_b));
fe_b = get_next_facet(fe_c);
}
}
}
popped = splitcount;
return popped;
}
/**********************************************************************
Vertex popping.
*************************************************************************/
#define OTHERCONE 0
#define WIREBOUNDARY 1
#define PLANECONE 2
#define WIREWING 3
#define WIRECORNER 4
#define TRIPLE_EDGER 5
#define TETRAHEDRAL 6
#define KRAYNIKCONE 7
#define CUBECONE 8
#define ODD4CONE 9
static facetedge_id *felist; /* for cell-ordered list */
/*************************************************************************
*
* Function: verpop_film()
*
* Purpose: Pop vertices with non-minimal tangent cones. Assumes
* all edges are at most triple edges.
*/
int verpop_film()
{
int popcount = 0;
while ( find_vertex_to_pop() )
{ popcount++;
}
return popcount;
}
/************************************************************************
*
* function: find_vertex_to_pop
*
* purpose: Looks through all vertices and finds one to pop. Whole
* process restarts after each pop since popping makes
* search lists obsolete.
*
* Returns number popped (0 or 1)
*/
int find_vertex_to_pop()
{
struct verfacet *vflist;
facetedge_id fe;
facet_id f_id;
int count,maxcount;
int spot,dups,conetype;
int popcount = 0;
/* Allocate list, with room for each facet thrice */
maxcount = 3*web.skel[FACET].count;
vflist = (struct verfacet *)temp_calloc(sizeof(struct verfacet),maxcount);
/* create unsorted list */
count = 0;
FOR_ALL_FACETS(f_id)
{
vflist[count].f_id = f_id;
fe = get_facet_fe(f_id);
vflist[count].v_id = get_fe_tailv(fe);
count++;
fe = get_next_edge(fe);
vflist[count].f_id = f_id;
vflist[count].v_id = get_fe_tailv(fe);
count++;
fe = get_next_edge(fe);
vflist[count].f_id = f_id;
vflist[count].v_id = get_fe_tailv(fe);
count++;
if ( count > maxcount )
{
kb_error(1300,
"Internal error: Not enough structures allocated for vertex-facet list.\n",
RECOVERABLE);
return 0;
}
}
/* sort by vertex order */
qsort((char *)vflist,count,sizeof(struct verfacet),FCAST vfcomp);
/* go through list and pop appropriate vertices */
for ( spot = 0 ; spot < count ; spot += dups )
{
vertex_id v_id = vflist[spot].v_id;
/* find how many successive duplicates of current vertex */
for ( dups = 1 ; spot+dups < count ; dups++ )
if ( !equal_id(vflist[spot+dups].v_id,v_id) ) break;
if ( get_vattr(v_id) & FIXED ) continue;
conetype = cone_analyze(vflist + spot,dups);
if ( conetype == KRAYNIKCONE )
popcount += kraynik_pop(v_id,dups);
else if ( conetype == CUBECONE )
popcount += cubecone_pop(v_id,dups);
else if ( conetype == ODD4CONE )
popcount += odd4cone_pop(v_id,dups);
else if ( conetype == OTHERCONE )
popcount += pop_vertex(v_id,dups);
temp_free((char *)felist);
if ( popcount ) break; /* one vertex at a time */
}
temp_free((char *)vflist);
return popcount;
}
/**************************************************************************
*
* function: pop_given_vertex()
*
* purpose: pop vertex specified by user.
*
*/
int pop_given_vertex(v_id)
vertex_id v_id;
{
struct verfacet *vflist;
facetedge_id fe,start_fe,loop_fe;
facet_id f_id;
int count,maxcount;
int spot,dups,conetype;
int popcount = 0;
int con_hits;
if ( !valid_id(get_vertex_edge(v_id)) )
{ if ( !(get_vattr(v_id) & FIXED) )
{ if ( verbose_flag )
{ sprintf(msg,"Dissolving bare vertex %s\n",ELNAME(v_id));
outstring(msg);
}
free_element(v_id);
return 1;
}
}
if ( web.representation == STRING ) return pop_string_vertex(v_id);
con_hits = v_hit_constraint_count(v_id);
if ( con_hits )
return pop_constrained_vertex(v_id);
/* Allocate list, with room for each facet thrice */
maxcount = 3*web.skel[FACET].count;
vflist = (struct verfacet *)temp_calloc(sizeof(struct verfacet),maxcount);
/* create unsorted list */
count = 0;
start_fe = get_vertex_first_facet(v_id);
loop_fe = start_fe;
if ( !valid_id(loop_fe) )
return 0;
do
{ f_id = get_fe_facet(loop_fe);
vflist[count].f_id = f_id;
fe = get_facet_fe(f_id);
vflist[count].v_id = get_fe_tailv(fe);
count++;
fe = get_next_edge(fe);
vflist[count].f_id = f_id;
vflist[count].v_id = get_fe_tailv(fe);
count++;
fe = get_next_edge(fe);
vflist[count].f_id = f_id;
vflist[count].v_id = get_fe_tailv(fe);
count++;
if ( count > maxcount )
{
kb_error(2526,
"Internal error: Not enough structures allocated for vertex-facet list.\n",
RECOVERABLE);
return 0;
}
loop_fe = get_next_vertex_facet(v_id,loop_fe);
} while ( !equal_element(loop_fe,start_fe));
/* sort by vertex order */
qsort((char *)vflist,count,sizeof(struct verfacet),FCAST vfcomp);
/* go through list and pop appropriate vertices */
for ( spot = 0 ; spot < count ; spot += dups )
{
if ( v_id != vflist[spot].v_id ) { dups = 1; continue; }
/* find how many successive duplicates of current vertex */
for ( dups = 1 ; spot+dups < count ; dups++ )
if ( !equal_id(vflist[spot+dups].v_id,v_id) ) break;
if ( get_vattr(v_id) & FIXED ) continue;
conetype = cone_analyze(vflist + spot,dups);
if ( conetype == KRAYNIKCONE )
popcount += kraynik_pop(v_id,dups);
else if ( conetype == CUBECONE )
popcount += cubecone_pop(v_id,dups);
else if ( conetype == ODD4CONE )
popcount += odd4cone_pop(v_id,dups);
else if ( conetype == OTHERCONE )
popcount += pop_vertex(v_id,dups);
temp_free((char *)felist);
break; /* one vertex at a time */
}
temp_free((char *)vflist);
return popcount;
}
/**************************************************************************
*
* function: figure_type()
*
* purpose: figure out what type of tangent cone a vertex has.
*
*/
#define CELLMAX 300
#define ARCMAX 600
static struct cell { int start; /* arc list start in arclist */
int festart; /* starting place in felist */
int num; /* number of arcs */
int fenum; /* number of facetedges */
REAL area; /* external angle deficit */
body_id b_id; /* which body, if any */
} cell[CELLMAX];
static struct arc { int start; /* edge list start in felist */
int num; /* number of edges */
int valence; /* number of arcs into head node */
/* int headtype; */ /* type of head node */
} arclist[ARCMAX];
static int cells;
int figure_type ARGS((int));
int figure_type(arcs)
int arcs;
{ int k,type;
/* Classifying cone */
switch ( cells )
{
case 1: /* wire boundary */
type = WIREBOUNDARY;
break;
case 2: switch ( arcs )
{
case 2: /* internal plane */
type = PLANECONE;
break;
case 4: /* two wings on wire boundary */
type = WIREWING; /* minimality depends on angle */
break;
default: /* n boundary wires meet at center */
type = WIRECORNER;
break;
}
break;
case 3: switch ( arcs )
{
case 6: /* triple edge */
type = TRIPLE_EDGER;
for ( k = 0 ; k < cells ; k++ )
if ( cell[k].num != 2 ) type = OTHERCONE;
break;
default:
type = OTHERCONE;
break;
}
break;
case 4: switch ( arcs )
{
case 12: /* maybe tetrahedral cone */
{ int twos=0,threes=0,fours=0;
for ( k = 0 ; k < cells ; k++ )
{ switch ( cell[k].num )
{ case 2: twos++; break;
case 3: threes++; break;
case 4: fours++; break;
}
}
if ( threes == 4 )
type = TETRAHEDRAL;
else if ( twos==2 && fours==2 )
type = ODD4CONE;
else type = OTHERCONE;
}
break;
default:
type = OTHERCONE;
break;
}
break;
case 5: if ( !kraynikpopvertex_flag || (arcs != 18) )
{ type = OTHERCONE; break; }
type = KRAYNIKCONE;
for ( k = 0 ; k < cells ; k++ )
if ( (cell[k].num < 3) || (cell[k].num > 4) )
{ type = OTHERCONE; break; }
break;
case 6: type = CUBECONE;
if ( arcs != 24 )
{ type = OTHERCONE; break; }
for ( k = 0 ; k < cells ; k++ )
if ( cell[k].num != 4 )
{ type = OTHERCONE; break; }
break;
default:
type = OTHERCONE;
break;
}
return type;
}
/***************************************************************************
*
* function: cone_analyze()
*
* purpose: construct tangent cone structure around vertex and
* return cone type from figure_type().
*
*/
int cone_analyze(vf,count)
struct verfacet *vf;
int count;
{
int type; /* final classification */
facetedge_id fe,nextfe,ray,nextray;
vertex_id v_id = vf->v_id;
int cellstart,arcstart,cellsides;
int arclen,valence;
int arcs;
int k,j;
int nodeflag; /* whether any interesting node has been found for cell */
/* First, set up network structure of edges opposite central vertex */
felist = (facetedge_id *)temp_calloc(sizeof(facetedge_id),2*count);
/* fill with outside edges of facets */
for ( k = 0 ; k < count ; k++ )
{
fe = get_facet_fe(vf[k].f_id);
if ( equal_id(v_id,get_fe_tailv(fe)) )
fe = get_next_edge(fe);
else if ( equal_id(v_id,get_fe_headv(fe)) )
fe = get_prev_edge(fe);
felist[2*k] = fe;
felist[2*k+1] = inverse_id(fe);
}
/* order into arcs and cell boundaries */
k = 0; /* current edge number */
cells = 0; /* current cell number */
arcs = 0; /* current arc number */
while ( k < 2*count )
{
CELLSTART:
/* starting new cell */
if ( k >= 2*count ) break;
if ( cells >= CELLMAX )
{ sprintf(errmsg,"pop: Too many cells around vertex %s in cone_analyze().\n",
ELNAME(v_id));
kb_error(1301,errmsg, RECOVERABLE);
}
nodeflag = 0; /* whether interesting node found on cell */
cellstart = k;
cellsides = 0;
cell[cells].start = arcs;
ARCSTART:
/* starting new arc */
if ( arcs >= ARCMAX )
{ sprintf(errmsg,"pop: Too many arcs around vertex %s in cone_analyze().\n",
ELNAME(v_id));
kb_error(1302,errmsg, RECOVERABLE);
}
arcstart = k;
arclist[arcs].start = arcstart;
ARCRESTART:
arclen = 0;
for (k = arcstart; k < 2*count ;k++)
{
/* starting next edge */
arclen++;
fe = felist[k];
nextray = ray = get_next_edge(fe);
for ( valence = 1 ; ; valence++ )
{ nextray = get_next_facet(nextray);
if ( equal_id(nextray,ray) ) break;
}
nextray = get_next_facet(ray);
nextfe = get_next_edge(inverse_id(nextray));
if ( equal_id(nextfe,felist[cellstart]) ) /* have gone around */
{
arclist[arcs].num = arclen;
arclist[arcs].valence = valence;
arcs++;
cellsides++;
cell[cells].num = cellsides;
cells++;
k++;
goto CELLSTART;
}
/* linear search list until nextfe found */
for ( j = k+1 ; j < 2*count ; j++ )
if ( equal_id(nextfe,felist[j]) ) break;
if ( !equal_id(nextfe,felist[j]) )
{ sprintf(errmsg,
"Internal error: cone_analyze vertex %s: can't find nextfe in felist.\n",
ELNAME(v_id));
kb_error(1303,errmsg,RECOVERABLE);
}
if ( j > k+1 ) /* swap into place */
{
felist[j] = felist[k+1];
felist[k+1] = nextfe;
}
/* see if node between is interesting */
if ( (valence != 2))
{ /* have interesting node */
if ( nodeflag == 0 )
{ /* first interesting node for cell */
/* reset felist so cell and arc start are same */
felist[k] = felist[arcstart];
felist[arcstart] = nextfe;
felist[k+1] = fe;
nodeflag = 1;
goto ARCRESTART;
}
arclist[arcs].num = arclen;
arclist[arcs].valence = valence;
arcs++;
cellsides++;
k++;
goto ARCSTART;
}
}
}
type = figure_type(arcs); /* so stupid SUN can optimize */
return type;
}
/*******************************************************************
*
* Function: pop_vertex()
*
* Purpose: pops one non-minimal vertex using info found by
* cone_analyze(). Finds areas of each face. All
* face cones are pulled out to sphere except largest
* area. Special treatment for face with disjoint
* boundary.
*/
int pop_vertex(v_id,count)
vertex_id v_id;
int count; /* number of entries in vflist */
{
int i,j,k,m;
struct arc *ar;
int fenum;
facetedge_id fe;
REAL cosdef;
REAL prevnormal[MAXCOORD],prevnorm;
REAL thisnormal[MAXCOORD],thisnorm;
REAL maxarea = 0.0;
int bigcell=0;
REAL total_area = 0.0;
REAL total_angle,angle;
REAL side[MAXCOORD],ray[MAXCOORD];
REAL *vx,newx[MAXCOORD];
edge_id ray_e;
facetedge_id ray_fe;
vertex_id new_v;
conmap_t *old_conmap;
int old_bdrynum = -1;
int samecell2, othercell2;
body_id bs1,bs2,bo1,bo2;
REAL totside1length,totside2length;
int flipflag = 0; /* if cones switched in widecones */
if ( verbose_flag )
{ sprintf(msg,"Popping vertex %s\n",ELNAME(v_id));
outstring(msg);
}
/* fix up cell structures */
for ( i = 0 ; i < cells ; i++ )
{ cell[i].fenum = 0;
ar = arclist + cell[i].start;
cell[i].festart = ar->start;
for ( j = 0 ; j < cell[i].num ; j++, ar++ )
cell[i].fenum += ar->num;
}
/* check for special configuration of touching disjoint cones
that may want to be merged rather than split
*/
if ( (cells == 4) && (cell[0].num == 1) && (cell[1].num == 1)
&& (cell[2].num == 1) && (cell[3].num == 1) )
{ REAL cosa,bestcosa;
facetedge_id bestray1=NULLID, bestray2=NULLID,fe_1,fe_2;
int samecell,othercell;
REAL area1,area2,normal1[MAXCOORD],normal2[MAXCOORD];
REAL totnorm1[MAXCOORD],totnorm2[MAXCOORD];
REAL axis1[MAXCOORD], axis2[MAXCOORD];
REAL side1[MAXCOORD], side2[MAXCOORD];
facet_id f_1,f_2,f_septum=NULLID;
REAL ratio;
int middleflag = 0; /* whether to put in septum */
facetedge_id first_fe3=NULLID, prev_fe3, newfe3;
body_id b_1, b_2;
/* first, see which cells are really the same cones */
samecell = 0;
for ( i = 1 ; i < cells ; i++ )
{ for ( j = 0 ; j < cell[0].fenum ; j++ )
for ( k = 0 ; k < cell[i].fenum ; k++ )
if (equal_element(felist[cell[0].festart+j],felist[cell[i].festart+k]))
{ samecell = i;
break;
}
}
if ( samecell == 0 )
{ sprintf(errmsg,"Vertex %s looks like double cones but isn't.\n",
ELNAME(v_id));
kb_error(2890,errmsg,RECOVERABLE);
}
othercell = (samecell == 1) ? 2 : 1;
/* get axis and see if cones wide enough to pop this way */
area1 = area2 = 0.0;
memset((char*)axis1,0,sizeof(axis1));
memset((char*)axis2,0,sizeof(axis2));
memset((char*)totnorm1,0,sizeof(totnorm1));
memset((char*)totnorm2,0,sizeof(totnorm2));
totside1length = totside2length = 0.0;
for ( i = 0 ; i < cell[samecell].fenum ; i++ )
{ fe_1 = felist[cell[samecell].festart+i];
f_1 = get_fe_facet(fe_1);
get_facet_normal(f_1,normal1);
area1 += sqrt(dot(normal1,normal1,SDIM));
for ( j = 0 ; j < SDIM ; j++ )
totnorm1[j] += normal1[j];
get_fe_side(get_prev_edge(fe_1),side1);
for ( j = 0 ; j < SDIM ; j++ )
axis1[j] += side1[j];
totside1length += sqrt(dot(side1,side1,SDIM));
}
for ( i = 0 ; i < cell[othercell].fenum ; i++ )
{ fe_2 = felist[cell[othercell].festart+i];
f_2 = get_fe_facet(fe_2);
get_facet_normal(f_2,normal2);
area2 += sqrt(dot(normal2,normal2,SDIM));
for ( j = 0 ; j < SDIM ; j++ )
totnorm2[j] += normal2[j];
get_fe_side(get_prev_edge(fe_2),side2);
for ( j = 0 ; j < SDIM ; j++ )
axis2[j] += side2[j];
totside2length += sqrt(dot(side2,side2,SDIM));
}
if ( pop_disjoin_flag ) goto narrowcones;
if ( pop_enjoin_flag ) goto widecones;
/* test wideness */
ratio = (sqrt(dot(totnorm1,totnorm1,SDIM))+sqrt(dot(totnorm2,totnorm2,SDIM)))
/(area1 + area2);
if ( ratio < (middleflag?0.94:0.88) )
goto narrowcones;
widecones:
/* choose cones to get facet normals going same way */
for ( j = 1 ; j < cells ; j++ )
if ( (j != samecell) && (j != othercell) ) break;
othercell2 = j;
samecell2 = 0;
/*
if ( dot(axis2,totnorm2,SDIM) < 0 )
{ int tmp = othercell;
othercell = othercell2;
othercell2 = tmp;
}
if ( dot(axis1,totnorm1,SDIM) > 0 )
{ samecell2 = samecell;
samecell = 0;
}
*/
if ( dot(totnorm1,totnorm2,SDIM) < 0 )
{ int tmp = othercell;
othercell = othercell2;
othercell2 = tmp;
for ( i = 0 ; i < SDIM ; i++ )
{ axis2[i] *= -1;
totnorm2[i] *= -1;
}
}
if ( dot(axis1,totnorm1,SDIM)/totside1length >
dot(axis2,totnorm1,SDIM)/totside2length )
{ int tmp = othercell; othercell = samecell; samecell = tmp;
tmp = samecell2; samecell2 = othercell2; othercell2 = tmp;
}
bs1 = get_facet_body(get_fe_facet(felist[cell[samecell].festart]));
bs2 = get_facet_body(get_fe_facet(felist[cell[samecell2].festart]));
bo1 = get_facet_body(get_fe_facet(felist[cell[othercell].festart]));
bo2 = get_facet_body(get_fe_facet(felist[cell[othercell2].festart]));
if ( !equal_id(bs2,bo1) )
{ /* have to flip sides */
int tmp;
body_id btmp;
if ( !equal_id(bs1,bo2) )
{ /* no matching sides. Shouldn't happen. */
return 0;
}
tmp = othercell; othercell = othercell2; othercell2 = tmp;
btmp = bs1; bs1 = bs2; bs2 = btmp;
tmp = samecell; samecell = samecell2; samecell2 = tmp;
btmp = bo1; bo1 = bo2; bo2 = btmp;
}
/* test bodies to see if we want septum */
fe_1 = felist[cell[samecell].festart];
f_1 = get_fe_facet(fe_1);
fe_2 = felist[cell[othercell].festart];
f_2 = get_fe_facet(fe_2);
b_1 = get_facet_body(f_1);
b_2 = get_facet_body(inverse_id(f_2));
if ( !valid_id(b_1) || !valid_id(b_2) || !equal_id(b_1,b_2) )
{ middleflag = 1;
f_septum = dup_facet(f_1);
set_facet_body(f_septum,b_1);
set_facet_body(inverse_id(f_septum),b_2);
}
/* now find closest rays on opposite cells */
bestcosa = -1.0;
for ( i = 0 ; i < cell[samecell].fenum ; i++ )
{ REAL edge1[MAXCOORD],edge2[MAXCOORD];
facetedge_id ray1 = get_prev_edge(felist[cell[samecell].festart+i]);
get_fe_side(ray1,edge1);
for ( j = 0 ; j < cell[othercell].fenum ; j++ )
{ facetedge_id ray2 = get_prev_edge(felist[cell[othercell].festart+j]);
get_fe_side(ray2,edge2);
cosa = dot(edge1,edge2,SDIM)/sqrt(dot(edge1,edge1,SDIM)*
dot(edge2,edge2,SDIM));
if ( cosa > bestcosa )
{ bestray1 = ray1; bestray2 = ray2; bestcosa = cosa; }
}
}
/* get lower number of sides in first cone */
if ( cell[samecell].fenum > cell[othercell].fenum )
{ int tmp = samecell;
facetedge_id fetmp = bestray1;
samecell = othercell;
othercell = tmp;
bestray1 = bestray2;
bestray2 = fetmp;
flipflag = 1;
}
/* go around, inserting edges */
fe_1 = bestray1;
fe_2 = bestray2;
prev_fe3 = NULLID;
for ( j = 0 ; j < cell[samecell].fenum ; j++ )
{ edge_id e_1,e_1next,e_2next,newe;
facetedge_id fe_1next,fe_2next,newfe1,newfe2;
facet_id f_1,f_2;
vertex_id newv;
REAL *x;
e_1 = get_fe_edge(fe_1);
fe_1next = inverse_id(get_prev_edge(fe_1));
e_1next = get_fe_edge(fe_1next);
fe_2next = inverse_id(get_prev_edge(fe_2));
e_2next = get_fe_edge(fe_2next);
f_1 = get_fe_facet(fe_1next);
f_2 = get_fe_facet(fe_2next);
if ( j < cell[samecell].fenum - 1 )
{ newv = dup_vertex(v_id);
remove_vertex_edge(v_id,e_1next);
remove_vertex_edge(v_id,e_2next);
set_edge_tailv(e_1next,newv);
set_edge_tailv(e_2next,newv);
}
else newv = v_id;
get_edge_side(e_1next,side1);
get_edge_side(e_2next,side2);
x = get_coord(newv);
for ( k = 0 ; k < SDIM ; k++ )
x[k] += 0.25*(side1[k]+side2[k]);
newe = new_edge(get_edge_tailv(e_1),newv,e_1);
newfe1 = new_facetedge(f_1,newe);
newfe2 = new_facetedge(f_2,newe);
set_edge_fe(newe,newfe1);
set_prev_facet(newfe1,newfe2);
set_next_facet(newfe2,newfe1);
set_prev_facet(newfe2,newfe1);
set_next_facet(newfe1,newfe2);
if ( middleflag )
{ newfe3 = new_facetedge(f_septum,newe);
if ( flipflag )
{
set_prev_facet(newfe3,newfe2);
set_next_facet(newfe2,newfe3);
set_prev_facet(newfe1,newfe3);
set_next_facet(newfe3,newfe1);
}
else
{
set_prev_facet(newfe3,newfe1);
set_next_facet(newfe1,newfe3);
set_prev_facet(newfe2,newfe3);
set_next_facet(newfe3,newfe2);
}
if ( valid_id(prev_fe3) )
{ set_next_edge(prev_fe3,newfe3);
set_prev_edge(newfe3,prev_fe3);
prev_fe3 = newfe3;
}
else
{ first_fe3 = newfe3;
set_facet_fe(f_septum,first_fe3);
prev_fe3 = newfe3;
}
}
set_next_edge(newfe1,fe_1next);
set_prev_edge(fe_1next,newfe1);
set_prev_edge(newfe1,inverse_id(fe_1));
set_next_edge(inverse_id(fe_1),newfe1);
set_next_edge(newfe2,fe_2next);
set_prev_edge(fe_2next,newfe2);
set_prev_edge(newfe2,inverse_id(fe_2));
set_next_edge(inverse_id(fe_2),newfe2);
cross_cut(newfe1,fe_1next);
cross_cut(newfe2,fe_2next);
fe_1 = get_next_facet(fe_1next);
fe_2 = get_next_facet(fe_2next);
}
if ( middleflag )
{ set_next_edge(prev_fe3,first_fe3);
set_prev_edge(first_fe3,prev_fe3);
if ( cell[samecell].fenum > 3 )
face_triangulate(f_septum,cell[samecell].fenum);
}
return 1;
narrowcones: ; /* bailout if not poppable this way */
}
/* see if any cells are totally detachable */
for ( i = 0 ; i < cells ; i++ )
{ vertex_id newv;
ar = arclist + cell[i].start;
if ( (cell[i].num != 1) || (ar->valence != 2) ) continue;
/* now have one */
newv = dup_vertex(v_id);
for ( j = 0 ; j < ar->num ; j++ )
{ fe = felist[ar->start+j];
ray_e = get_fe_edge(get_next_edge(fe));
remove_vertex_edge(v_id,inverse_id(ray_e));
set_edge_headv(ray_e,newv);
}
return 1; /* safe to do only one at a time */
}
/* calculate areas of each cell */
for ( i = 0 ; i < cells ; i++ )
{
total_angle = 0.0;
fenum = cell[i].festart;
fe = felist[fenum+cell[i].fenum-1];
cell[i].b_id = get_facet_body(get_fe_facet(inverse_id(fe)));
get_fe_side(fe,side);
get_fe_side(get_prev_edge(fe),ray);
cross_prod(ray,side,prevnormal);
prevnorm = sqrt(SDIM_dot(prevnormal,prevnormal));
for ( k = 0 ; k < cell[i].fenum ; k++,fenum++ )
{
fe = felist[fenum];
get_fe_side(fe,side);
get_fe_side(get_prev_edge(fe),ray);
cross_prod(ray,side,thisnormal);
thisnorm = sqrt(SDIM_dot(thisnormal,thisnormal));
cosdef = SDIM_dot(prevnormal,thisnormal)/prevnorm/thisnorm;
if ( cosdef > 1.0 ) angle = 0.0;
else if ( cosdef < -1.0 ) angle = M_PI;
else angle = acos(cosdef);
if ( SDIM_dot(side,prevnormal) > 0.0 )
total_angle += angle;
else
total_angle -= angle; /* in case cell not convex */
/* set up for next loop */
prevnorm = thisnorm;
memcpy((char *)prevnormal,(char *)thisnormal,sizeof(prevnormal));
}
cell[i].area = 2*M_PI - total_angle;
total_area += cell[i].area;
}
/* kludge to adjust for 2*pi ambiguity in turning angle that can
affect badly shaped cells */
while ( total_area > 4*M_PI + 1 )
{ int maxi = -1;
REAL maxa = -1e30;
for ( i = 0 ; i < cells ; i++ )
if ( cell[i].area > maxa )
{ maxi = i; maxa = cell[i].area; }
cell[maxi].area -= 2*M_PI;
total_area -= 2*M_PI;
}
while ( total_area < 4*M_PI - 1)
{ int mini = -1;
REAL mina = 1e30;
for ( i = 0 ; i < cells ; i++ )
if ( cell[i].area < mina )
{ mini = i; mina = cell[i].area; }
cell[mini].area += 2*M_PI;
total_area += 2*M_PI;
}
if ( total_area < 4*M_PI - 0.00001 )
{ sprintf(errmsg,
"Solid angle deficit %g found around vertex %s. Not popped.\n",
(double)(4*M_PI-total_area), ELNAME(v_id));
kb_error(2176,errmsg,WARNING);
return 0;
}
if ( total_area > 4*M_PI + 0.00001 )
{ sprintf(errmsg,
"Solid angle excess %g found around vertex %s. Not popped.\n",
(double)(total_area-4*M_PI), ELNAME(v_id));
kb_error(2177,errmsg,WARNING);
return 0;
}
/* see which cell is the largest */
for ( i = 0 ; i < cells ; i++ )
if ( cell[i].area > maxarea )
{ bigcell = i; maxarea = cell[i].area; }
/* Now go around covering over all cells but bigcell or cells
bigger than hemisphere */
/* First, put new endpoint on all edges coming into v_id */
vx = get_coord(v_id);
old_conmap = get_v_constraint_map(v_id);
if ( get_vattr(v_id) & BOUNDARY )
{ old_bdrynum = get_vertex_boundary_num(v_id);
}
for ( j = 0 ; j < 2*count ; j++ )
{ REAL rayvec[MAXCOORD];
fe = felist[j];
ray_fe = get_prev_edge(fe);
if ( !equal_id(v_id,get_fe_tailv(ray_fe)) ) continue; /* done this */
ray_e = get_fe_edge(ray_fe);
get_edge_side(ray_e,rayvec);
for ( m = 0 ; m < SDIM ; m++ )
newx[m] = 0.5*rayvec[m] + vx[m];
new_v = new_vertex(newx,ray_e);
remove_vertex_edge(v_id,ray_e);
set_edge_tailv(ray_e,new_v);
if ( old_bdrynum >= 0 )
set_vertex_boundary_num(new_v,old_bdrynum);
else
set_v_conmap(new_v,old_conmap);
}
/* divide up old facets */
for ( j = 0 ; j < 2*count ; j++ )
{ facetedge_id new_fe,new_fe_next,new_fe_prev;
facetedge_id inray_fe;
vertex_id v1,v2;
edge_id new_e;
fe = felist[j];
ray_fe = get_prev_edge(fe);
inray_fe = get_next_edge(fe);
v1 = get_fe_tailv(ray_fe);
v2 = get_fe_headv(inray_fe);
/* Each facet gets covered twice. First time we put in edge;
second time triangulate the quadrilateral. This way we
can substitute the new inner fe for the old outer fe
in felist.
*/
if ( equal_id(inray_fe,get_prev_edge(ray_fe)) )
{ /* first time around */
/* put in new edge */
new_e = new_edge(v2,v1,get_fe_facet(fe));
new_fe = new_facetedge(get_fe_facet(fe),new_e);
set_edge_fe(new_e,new_fe);
set_next_edge(inray_fe,new_fe);
set_prev_edge(new_fe,inray_fe);
set_next_edge(new_fe,ray_fe);
set_prev_edge(ray_fe,new_fe);
if ( old_bdrynum >= 0 )
set_edge_boundary_num(new_e,old_bdrynum);
else
set_e_conmap(new_e,old_conmap);
/* stub fe's for cells on each side */
new_fe_prev = new_facetedge(NULLFACET,new_e);
new_fe_next = new_facetedge(NULLFACET,new_e);
set_next_facet(new_fe,new_fe_next);
set_next_facet(new_fe_next,new_fe_prev);
set_next_facet(new_fe_prev,new_fe);
set_prev_facet(new_fe,new_fe_prev);
set_prev_facet(new_fe_prev,new_fe_next);
set_prev_facet(new_fe_next,new_fe);
felist[j] = inverse_id(new_fe_next); /* new inner fe */
}
else
{ felist[j] = inverse_id(get_next_facet(get_next_edge(inray_fe)));
divide_quad(fe);
}
}
/* now connect up insides of cells */
for ( i = 0 ; i < cells ; i++ )
{
facet_id new_f=0,old_f;
facetedge_id prev_fe=0; /* last in edge chain */
fenum = cell[i].festart;
if ( (i != bigcell) && (cell[i].area < 2*M_PI) )
{ prev_fe = felist[fenum+cell[i].fenum-1];
old_f = facet_inverse(get_fe_facet(get_next_facet(prev_fe)));
new_f = dup_facet(old_f);
set_facet_body(new_f,cell[bigcell].b_id);
set_facet_body(inverse_id(new_f),cell[i].b_id);
set_facet_fe(new_f,prev_fe);
}
for ( k = 0 ; k < cell[i].fenum ; k++,fenum++ )
{
fe = felist[fenum];
if ( (i == bigcell) || (cell[i].area >= 2*M_PI) )
{ /* have to excise fe */
set_prev_facet(get_next_facet(fe),get_prev_facet(fe));
set_next_facet(get_prev_facet(fe),get_next_facet(fe));
free_element(fe);
}
else
{ /* hook into edge loop around facet */
set_prev_edge(fe,prev_fe);
set_next_edge(prev_fe,fe);
set_fe_facet(fe,new_f);
prev_fe = fe;
}
}
/* if necessary, triangulate new cell facet */
if ( (i != bigcell) && (cell[i].area < 2*M_PI) )
{ if ( cell[i].fenum >= 5 )
face_triangulate(new_f,cell[i].fenum);
else if ( cell[i].fenum == 4 )
divide_quad(get_facet_fe(new_f));
}
}
/* free original central vertex */
free_element(v_id);
return 1;
}
/*******************************************************************
*
* Function: kraynik_pop()
*
* Purpose: pops one non-minimal vertex of type KRAYNIKCONE.
*/
int kraynik_pop(v_id,count)
vertex_id v_id;
int count; /* number of entries in vflist */
{
int i,j,k,m,kk;
struct arc *ar;
facetedge_id fe;
vertex_id newv;
edge_id newe;
edge_id head_triples[3],tail_triples[3];
REAL tailside[MAXCOORD],headside[MAXCOORD];
REAL tailforce[MAXCOORD],headforce[MAXCOORD];
REAL mag;
/* find the 3-arc cells */
for ( k = 0 ; k < cells ; k++ )
if ( cell[k].num == 3 ) break;
for ( kk = k+1 ; kk < cells ; kk++ )
if ( cell[kk].num == 3 ) break;
if ( kk == cells )
return 0; /* failure */
for ( i = 0 ; i < SDIM ; i++ )
tailforce[i] = headforce[i] = 0.0;
/* get triple lines and vectors to see which way to pop */
for ( m = 0 ; m < 3 ; m++ )
{ ar = arclist + cell[k].start + m;
fe = felist[ar->start];
tail_triples[m] = get_fe_edge(get_prev_edge(fe));
get_edge_side(tail_triples[m],tailside);
mag = sqrt(dot(tailside,tailside,SDIM));
if ( mag != 0 )
for ( i = 0 ; i < SDIM ; i++ )
tailforce[i] += tailside[i]/mag;
ar = arclist + cell[kk].start + m;
fe = felist[ar->start];
head_triples[m] = get_fe_edge(get_prev_edge(fe));
get_edge_side(head_triples[m],headside);
mag = sqrt(dot(headside,headside,SDIM));
if ( mag != 0 )
for ( i = 0 ; i < SDIM ; i++ )
headforce[i] += headside[i]/mag;
}
if ( pop_to_face_flag || ( !pop_to_edge_flag &&
(dot(headforce,headforce,SDIM)+dot(tailforce,tailforce,SDIM) < 3)) )
return pop_vertex_to_tri(v_id,tail_triples);
newv = dup_vertex(v_id);
newe = new_edge(newv,v_id,NULLID);
/* go around the 3 arcs and reconfigure */
for ( m = 0 ; m < 3 ; m++ )
{ facetedge_id ray_fe,other_ray_fe,third_ray_fe;
facetedge_id newfe_a,newfe_b,newfe_c;
edge_id ray_e,newray_e;
facet_id newf;
ar = arclist + cell[k].start + m;
for ( j = 0 ; j < ar->num ; j++ )
{ fe = felist[ar->start+j];
ray_e = get_fe_edge(get_next_edge(fe));
remove_vertex_edge(v_id,inverse_id(ray_e));
set_edge_headv(ray_e,newv);
}
/* last one for splitting triple edge */
j = ar->num-1;
fe = felist[ar->start+j];
ray_fe = get_next_edge(fe);
ray_e = get_fe_edge(ray_fe);
newray_e = dup_edge(ray_e);
set_edge_headv(newray_e,v_id);
set_edge_tailv(newray_e,get_edge_tailv(ray_e));
other_ray_fe = inverse_id(get_prev_edge(felist[(ar+(m==2?-2:1))->start]));
third_ray_fe = get_next_facet(ray_fe);
if ( equal_id(third_ray_fe,other_ray_fe) )
third_ray_fe = get_prev_facet(ray_fe);
newf = dup_facet(get_fe_facet(third_ray_fe));
newfe_a = new_facetedge(newf,newe);
newfe_b = new_facetedge(newf,inverse_id(newray_e));
newfe_c = new_facetedge(newf,ray_e);
set_facet_fe(newf,newfe_a);
if ( m == 0 ) set_edge_fe(newe,newfe_a);
set_next_edge(newfe_a,newfe_b);
set_next_edge(newfe_b,newfe_c);
set_next_edge(newfe_c,newfe_a);
set_prev_edge(newfe_a,newfe_c);
set_prev_edge(newfe_b,newfe_a);
set_prev_edge(newfe_c,newfe_b);
if ( equal_id(ray_fe,get_next_facet(other_ray_fe)) )
{
set_next_facet(ray_fe,newfe_c);
set_prev_facet(newfe_c,ray_fe);
set_prev_facet(other_ray_fe,newfe_c);
set_next_facet(newfe_c,other_ray_fe);
}
else
{
set_prev_facet(ray_fe,newfe_c);
set_next_facet(newfe_c,ray_fe);
set_next_facet(other_ray_fe,newfe_c);
set_prev_facet(newfe_c,other_ray_fe);
}
set_edge_fe(ray_e,ray_fe);
set_edge_fe(newray_e,third_ray_fe);
set_next_facet(third_ray_fe,inverse_id(newfe_b));
set_prev_facet(third_ray_fe,inverse_id(newfe_b));
set_next_facet(inverse_id(newfe_b),third_ray_fe);
set_prev_facet(inverse_id(newfe_b),third_ray_fe);
set_fe_edge(third_ray_fe,newray_e);
set_edge_fe(newray_e,third_ray_fe);
if ( m == 1 )
{ set_next_facet(newfe_a,get_edge_fe(newe));
set_prev_facet(newfe_a,get_edge_fe(newe));
set_next_facet(get_edge_fe(newe),newfe_a);
set_prev_facet(get_edge_fe(newe),newfe_a);
}
else if ( m == 2 )
{ facetedge_id fe1 = get_edge_fe(newe);
facetedge_id fe2 = get_next_facet(fe1);
set_next_facet(newfe_a,fe2);
set_prev_facet(fe2,newfe_a);
set_prev_facet(newfe_a,fe1);
set_next_facet(fe1,newfe_a);
}
}
/* move a bit to avoid zero area facets */
new_vertex_average(newv,RAWEST);
new_vertex_average(v_id,RAWEST);
return 1; /* success */
}
/*******************************************************************
*
* Function: cubecone_pop()
*
* Purpose: pops one non-minimal vertex of type CUBECONE.
* Inserts central square in most favorable orientation.
*/
int cubecone_pop(v_id,count)
vertex_id v_id;
int count; /* number of entries in vflist */
{
int i,k,m;
struct arc *ar;
facetedge_id fe;
REAL side[MAXCOORD];
REAL faceforce[MAXCOORD];
REAL facemag,bestmag,mag;
int bestk=0;
edge_id triples[6][4];
/* find mean triple edge vectors for each face */
/* get triple lines and vectors to see which way to pop */
bestmag = 1e20;
for ( k = 0 ; k < 6 ; k++ )
{ for ( i = 0 ; i < SDIM ; i++ )
faceforce[i] = 0.0;
for ( m = 0 ; m < 4 ; m++ )
{ ar = arclist + cell[k].start + m;
fe = felist[ar->start];
triples[k][m] = get_fe_edge(get_prev_edge(fe));
get_edge_side( triples[k][m],side);
mag = sqrt(dot(side,side,SDIM));
if ( mag != 0 )
for ( i = 0 ; i < SDIM ; i++ )
faceforce[i] += side[i]/mag;
}
facemag = sqrt(dot(faceforce,faceforce,SDIM));
if ( facemag < bestmag )
{ bestmag = facemag;
bestk = k;
}
}
return pop_vertex_to_quad(v_id,triples[bestk]);
}
/********************************************************************
*
* Function: facet_force_on_vertex()
*
* Purpose: Calculate force of a facet on one of its vertices,
* force due to surface tension with density. For
* determining pop directions. Note the vector in fvec
* is the force, i.e. the negative of the area gradient.
*/
void facet_force_on_vertex(f_id,v_id,fvec)
facet_id f_id;
vertex_id v_id;
REAL *fvec; /* returned force */
{
REAL sides[2][MAXCOORD];
MAT2D(vx,FACET_VERTS,MAXCOORD);
int i,j,basei=0;
facetedge_id fe;
REAL s1s1,s1s2,s2s2,det;
REAL tension = get_facet_density(f_id);
REAL coeff;
get_facet_verts(f_id,vx,NULL);
fe = get_facet_fe(f_id);
for ( i = 0 ; i < FACET_EDGES ; i++ )
{
if ( equal_id(get_fe_tailv(fe),v_id) )
basei = i;
fe = get_next_edge(fe);
}
for ( j = 0 ; j < SDIM ; j++ )
{ sides[0][j] = vx[1][j] - vx[0][j];
sides[1][j] = vx[2][j] - vx[0][j];
}
s1s1 = dot(sides[0],sides[0],SDIM);
s2s2 = dot(sides[1],sides[1],SDIM);
s1s2 = dot(sides[0],sides[1],SDIM);
det = s1s1*s2s2 - s1s2*s1s2;
if ( det <= 0.0 )
{ for ( j = 0 ; j < SDIM ; j++ )
fvec[j] = 0.0;
}
coeff = tension/2/sqrt(det);
if ( basei == 0 )
{ for ( j = 0 ; j < SDIM ; j++ )
fvec[j] = coeff*((s2s2*sides[0][j] - s1s2*sides[1][j])
+ (s1s1*sides[1][j] - s1s2*sides[0][j]));
}
else if ( basei == 1 )
{ for ( j = 0 ; j < SDIM ; j++ )
fvec[j] = -coeff*(s2s2*sides[0][j] - s1s2*sides[1][j]);
}
else
{ for ( j = 0 ; j < SDIM ; j++ )
fvec[j] = -coeff*(s1s1*sides[1][j] - s1s2*sides[0][j]);
}
} /* end facet_force_on_vertex() */
/*******************************************************************
*
* Function: odd4cone_pop()
*
* Purpose: pops one non-minimal vertex of type ODD4CONE,
* which is two triple lines touching at the vertex.
* Can either detach the triple lines or split into
* two tetrahedral points with septum between.
*/
int odd4cone_pop(v_id,count)
vertex_id v_id;
int count; /* number of entries in vflist */
{
int i,j,k;
facetedge_id fe_a=NULLID,fe_b=NULLID; /* triple edge fe's on septum side*/
facetedge_id fe_c=NULLID,fe_d=NULLID; /* other pair of triple edge fe's */
edge_id e_a, e_b, e_c, e_d; /* triple edges */
facet_id f_a,f_b,f_c, f_d; /* septum facets */
REAL veca[MAXCOORD],vecb[MAXCOORD],vecc[MAXCOORD],vecd[MAXCOORD];
REAL vecab[MAXCOORD],vecac[MAXCOORD],veccd[MAXCOORD],vecbd[MAXCOORD];
int flag;
int split_cell=0;
int cdswap = 0;
REAL tripnetforce; /* force towards separate triples; pos favorable */
REAL quadnetforce; /* force towards quad line; pos favorable */
facetedge_id next_fe,fe;
REAL ee,ea,eb,ec,ed,aa,bb,cc,dd,bd,ac,acac,bdbd;
REAL eside[MAXCOORD];
int counter;
/* identify key parts */
/* find two triple lines on one side */
for ( i = 0, flag = 0 ; i < cells ; i++ )
{ if ( cell[i].num == 2 )
{ if ( flag )
{ fe_c = felist[arclist[cell[i].start].start]; /* outer fe */
fe_c = get_prev_edge(fe_c); /* radial fe */
fe_c = get_prev_facet(fe_c); /* on septum */
fe_d = felist[arclist[cell[i].start+1].start];
fe_d = get_prev_edge(fe_d); /* radial fe */
fe_d = get_prev_facet(fe_d); /* on septum */
}
else
{ fe_a = felist[arclist[cell[i].start].start]; /* outer fe */
fe_a = get_prev_edge(fe_a); /* radial fe */
fe_a = get_prev_facet(fe_a); /* on septum */
fe_b = felist[arclist[cell[i].start+1].start];
fe_b = get_prev_edge(fe_b); /* radial fe */
fe_b = get_prev_facet(fe_b); /* on septum */
split_cell = i;
flag = 1;
}
}
}
/* get a and c on same side of vertex */
next_fe = fe_a;
counter = 0;
for(;;)
{ next_fe = inverse_id(get_prev_edge(next_fe));
if ( equal_id(next_fe,fe_c) || equal_id(next_fe,fe_d))
break;
if ( !equal_id(get_next_facet(next_fe),get_prev_facet(next_fe)) || (++counter > 100) )
{ sprintf(errmsg,"Internal: Cannot match fe_c with fe_a at vertex %s; skipping pop.\n",
ELNAME(v_id));
kb_error(3692,errmsg,RECOVERABLE);
return 0;
}
next_fe = get_next_facet(next_fe);
}
if ( equal_id(next_fe,fe_d) )
{ /* swap c and d */
facetedge_id temp = fe_c;
fe_c = fe_d;
fe_d = temp;
cdswap = 1;
}
/* more parts */
e_a = get_fe_edge(fe_a);
e_b = get_fe_edge(fe_b);
e_c = get_fe_edge(fe_c);
e_d = get_fe_edge(fe_d);
f_a = get_fe_facet(fe_a);
f_b = get_fe_facet(fe_b);
f_c = get_fe_facet(fe_c);
f_d = get_fe_facet(fe_d);
get_edge_side(e_a,veca);
get_edge_side(e_b,vecb);
get_edge_side(e_c,vecc);
get_edge_side(e_d,vecd);
for ( i = 0 ; i < SDIM ; i++ )
{ vecab[i] = (veca[i] + vecb[i])/4;
veccd[i] = (vecc[i] + vecd[i])/4;
vecac[i] = (veca[i] + vecc[i])/4;
vecbd[i] = (vecb[i] + vecd[i])/4;
}
/* determine which way to split */
/* First, if pull triple lines apart*/
tripnetforce = 0.0;
for ( i = 0, flag = 0 ; i < cells ; i++ )
{ /* forces from existing facets */
if ( cell[i].num == 2 )
{ for ( k = 0 ; k < cell[i].num ; k++ )
{ struct arc *a = arclist + cell[i].start + k;
for ( j = 0 ; j < a->num ; j++ )
{ facetedge_id fe = felist[a->start + j];
REAL force[MAXCOORD];
facet_force_on_vertex(get_fe_facet(fe),v_id,force);
if ( flag )
tripnetforce += dot(veccd,force,SDIM);
else
tripnetforce += dot(vecab,force,SDIM);
}
}
flag = 1;
}
}
/* force from introduced facets */
ee = dot(vecab,vecab,SDIM);
aa = dot(veca,veca,SDIM);
ea = dot(veca,vecab,SDIM);
tripnetforce -= sqrt(aa*ee - ea*ea)/2*get_facet_density(f_a);
bb = dot(vecb,vecb,SDIM);
eb = dot(vecb,vecab,SDIM);
tripnetforce -= sqrt(bb*ee - eb*eb)/2*get_facet_density(f_b);
ee = dot(veccd,veccd,SDIM);
cc = dot(vecc,vecc,SDIM);
ec = dot(vecc,veccd,SDIM);
tripnetforce -= sqrt(cc*ee - ec*ec)/2*get_facet_density(f_c);
dd = dot(vecd,vecd,SDIM);
ed = dot(vecd,veccd,SDIM);
tripnetforce -= sqrt(dd*ee - ed*ed)/2*get_facet_density(f_d);
/* now force from expanding vertex to quad line */
/* assuming splits at the a->num/2 edge in the side arcs */
quadnetforce = 0.0;
for ( i = 0, flag = 0 ; i < cells ; i++ )
{ if ( cell[i].num == 2 )
{ for ( k = 0 ; k < cell[i].num ; k++ )
{ struct arc *a = arclist + cell[i].start + k;
for ( j = 0 ; j < a->num ; j++ )
{ facetedge_id fe = felist[a->start + j];
REAL force[MAXCOORD];
facet_force_on_vertex(get_fe_facet(fe),v_id,force);
if ( !flag || !cdswap )
{
if ( ((k==0) && (j < a->num/2)) || ((k==1)&&(j >= a->num/2)) )
quadnetforce += dot(vecac,force,SDIM);
else
quadnetforce += dot(vecbd,force,SDIM);
}
else
{ if ( ((k==0) && (j < a->num/2)) || ((k==1)&&(j >= a->num/2)) )
quadnetforce += dot(vecbd,force,SDIM);
else
quadnetforce += dot(vecac,force,SDIM);
}
}
}
flag = 1;
}
}
/* force from old septa */
ac = dot(veca,vecc,SDIM);
quadnetforce += sqrt(aa*cc-ac*ac)/4*get_facet_density(f_a);
bd = dot(vecb,vecd,SDIM);
quadnetforce += sqrt(bb*dd-bd*bd)/4*get_facet_density(f_b);
/* force from introduced facets */
for ( i = 0 ; i < cells ; i++ )
{ if ( cell[i].num == 2 )
{ for ( k = 0 ; k < cell[i].num ; k++ )
{ struct arc *a = arclist + cell[i].start + k;
REAL tension;
fe = felist[a->start + a->num/2];
fe = get_prev_edge(fe);
get_edge_side(get_fe_edge(fe),eside);
ee = dot(eside,eside,SDIM);
tension = get_facet_density(get_fe_facet(fe));
acac = dot(vecac,vecac,SDIM);
ea = dot(vecac,eside,SDIM);
quadnetforce -= sqrt(acac*ee - ea*ea)/2*tension;
bdbd = dot(vecbd,vecbd,SDIM);
eb = dot(vecbd,eside,SDIM);
quadnetforce -= sqrt(bdbd*ee - eb*eb)/2*tension;
}
}
}
if ( (tripnetforce < 0) && (quadnetforce < 0) )
{ if ( verbose_flag )
{ sprintf(msg,"Not popping touching-triple-lines vertex %s since stable.\n",
ELNAME(v_id));
outstring(msg);
}
return 0; /* no profit from splitting either way */
}
/* if separate triple lines */
if ( tripnetforce > quadnetforce )
{ vertex_id newv = dup_vertex(v_id);
edge_id newe;
facetedge_id fe_aa,fe_bb,new_fe_a,new_fe_b;
REAL *xold = get_coord(v_id);
REAL *xnew = get_coord(newv);
if ( verbose_flag )
{ sprintf(msg,"Separating triple lines at vertex %s.\n",
ELNAME(v_id));
outstring(msg);
}
/* spread vertices apart */
for ( i = 0 ; i < SDIM ; i++ )
{
xnew[i] += vecab[i];
xold[i] += veccd[i];
}
/* reconnected other edges on split-off part */
for ( i = 0 ; i < cell[split_cell].num ; i++ )
{ struct arc *a = arclist + cell[split_cell].start + i;
for ( j = 0 ; j < a->num ; j++ )
{ facetedge_id fe = felist[a->start + j];
edge_id e_id;
fe = get_prev_edge(fe);
e_id = get_fe_edge(fe);
set_edge_tailv(e_id,newv);
}
}
/* new edge and its facetedges */
newe = new_edge(v_id,newv,v_id);
new_fe_a = new_facetedge(f_a,newe);
new_fe_b = new_facetedge(f_b,newe);
set_edge_fe(newe,new_fe_a);
set_next_facet(new_fe_a,new_fe_b);
set_prev_facet(new_fe_a,new_fe_b);
set_next_facet(new_fe_b,new_fe_a);
set_prev_facet(new_fe_b,new_fe_a);
fe_aa = get_prev_edge(fe_a);
set_next_edge(new_fe_a,fe_a);
set_prev_edge(fe_a,new_fe_a);
set_prev_edge(new_fe_a,fe_aa);
set_next_edge(fe_aa,new_fe_a);
fe_bb = get_prev_edge(fe_b);
set_next_edge(new_fe_b,fe_b);
set_prev_edge(fe_b,new_fe_b);
set_prev_edge(new_fe_b,fe_bb);
set_next_edge(fe_bb,new_fe_b);
/* subdivide septum quadrilaterals */
cross_cut(new_fe_a,fe_a);
cross_cut(new_fe_b,fe_b);
}
else
{ /* split vertex to form quadruple line */
vertex_id newv = dup_vertex(v_id);
edge_id newe;
REAL *xold = get_coord(v_id);
REAL *xnew = get_coord(newv);
if ( verbose_flag )
{ sprintf(msg,"Inserting new septum at vertex %s.\n",
ELNAME(v_id));
outstring(msg);
}
/* spread vertices apart */
for ( i = 0 ; i < SDIM ; i++ )
{
xnew[i] += vecac[i];
xold[i] += vecbd[i];
}
/* new edge and its facetedges */
newe = new_edge(v_id,newv,v_id);
/* reconnected other edges on split-off part */
set_edge_tailv(e_a,newv);
set_edge_tailv(e_c,newv);
for ( i = 0, flag = 0 ; i < cells ; i++ )
{ if ( cell[i].num != 2 )
continue;
for ( k = 0 ; k < cell[i].num ; k++ )
{ struct arc *a = arclist + cell[i].start + k;
int upflag = (!flag && (k==0)) || (flag && !cdswap && (k==0))
|| (flag && cdswap && (k==1)) ;
facet_id ff;
facetedge_id new_fe,fe_prev,e_fe;
for ( j = 1 ; j < a->num ; j++ )
{ facetedge_id fe = felist[a->start + j];
edge_id e_id;
fe = get_prev_edge(fe);
e_id = get_fe_edge(fe);
if ( (upflag && (j <= a->num/2)) || (!upflag && (j >= a->num/2)) )
set_edge_tailv(e_id,newv);
}
/* now expand some facets to quads */
fe = felist[a->start + a->num/2];
fe = get_prev_edge(fe);
if ( !upflag )
fe = get_next_facet(fe);
ff = get_fe_facet(fe);
new_fe = new_facetedge(ff,newe);
fe_prev = get_prev_edge(fe);
set_prev_edge(new_fe,fe_prev);
set_next_edge(fe_prev,new_fe);
set_next_edge(new_fe,fe);
set_prev_edge(fe,new_fe);
e_fe = get_edge_fe(newe);
if ( valid_id(e_fe) )
{ fe_prev = get_prev_facet(e_fe);
set_next_facet(fe_prev,new_fe);
set_prev_facet(new_fe,fe_prev);
set_prev_facet(e_fe,new_fe);
set_next_facet(new_fe,e_fe);
}
else
{ set_edge_fe(newe,new_fe);
set_next_facet(new_fe,new_fe);
set_prev_facet(new_fe,new_fe);
}
cross_cut(new_fe,fe);
}
flag = 1;
}
fe_reorder(newe);
pop_one_edge(newe);
}
return 1;
} /* end odd4cone_pop() */
/*****************************************************************************
*
* function: pop_tri_to_edge()
*
* purpose: Topology change of small triangle to edge perpendicular to it.
* Implements pop_tri_to_edge command.
*
* return: 1 for success, 0 for failure.
*/
int pop_tri_to_edge(f_id)
facet_id f_id;
{ edge_id ea,eb,ec,newe;
vertex_id va,vb,vc,keepv=NULLID,newv;
facetedge_id fe,next_fe,fa,fb,fc;
int retval,i,j;
int legs;
REAL side[MAXCOORD],separation[MAXCOORD];
edge_id trip[3];
REAL *keepx,*newx;
edge_id tredges[12];
int ti;
if ( (web.modeltype != LINEAR) && (web.modeltype != QUADRATIC) )
kb_error(3366,"pop_tri_to_edge only for LINEAR or QUADRATIC models.\n",
RECOVERABLE);
/* Test geometry is appropriate */
next_fe = fe = get_facet_fe(f_id);
ti = 0;
do
{ int triples;
ea = get_fe_edge(next_fe);
ec = inverse_id(get_fe_edge(get_prev_edge(next_fe)));
if ( get_edge_valence(ea) != 3 )
{ if ( verbose_flag )
{ sprintf(msg,
"pop_tri_to_edge fails on facet %s; not all its edges triple .\n",
ELNAME(f_id));
outstring(msg);
}
return 0;
}
va = get_fe_tailv(next_fe);
eb = get_next_tail_edge(ea);
triples = 1;
while ( !equal_id(ea,eb) )
{ int val = get_edge_valence(eb);
if ( (val < 2) || ( val > 3 ) )
{ if ( verbose_flag )
{ sprintf(msg,
"pop_tri_to_edge fails on facet %s due to edge %s having valence %d.\n",
ELNAME(f_id),ELNAME1(eb),val);
outstring(msg);
}
return 0;
}
if ( (val == 3) && !equal_id(eb,ec) )
{ tredges[ti++] = eb;
triples++;
}
eb = get_next_tail_edge(eb);
}
if ( triples != 3 )
{ if ( verbose_flag )
{ sprintf(msg,
"pop_tri_to_edge fails on facet %s due to %d triple edges on vertex %s; need 4.\n",
ELNAME(f_id),triples+1,ELNAME1(get_edge_tailv(eb)));
outstring(msg);
}
return 0;
}
next_fe = get_next_edge(next_fe);
} while ( !equal_id(fe,next_fe) );
fe = get_facet_fe(f_id);
ea = get_fe_edge(fe);
eb = get_fe_edge(get_next_edge(fe));
ec = get_fe_edge(get_prev_edge(fe));
va = get_edge_tailv(ea);
vb = get_edge_tailv(eb);
vc = get_edge_tailv(ec);
/* check for disjoint endpoints of triple edges */
for ( i = 1 ; i < ti ; i++ )
for ( j = 0 ; j < i ; j++ )
if ( equal_id(get_edge_headv(tredges[i]),get_edge_headv(tredges[j])) )
{ if ( verbose_flag )
{ sprintf(msg,"pop_tri_to_edge fails on facet %s due to outer triple edges with common endpoint.\n",ELNAME(f_id));
outstring(msg);
}
return 0;
}
if ( verbose_flag )
{ sprintf(msg,"pop_tri_to_edge on facet %s\n",ELNAME(f_id));
outstring(msg);
}
retval = eliminate_facet(f_id);
if ( retval == 0 ) return 0;
/* now finish elimination by eliminating the remaining facet edge */
if ( valid_element(ea) )
{ retval = eliminate_edge(ea); free_element(ea); }
else if ( valid_element(eb) )
{ retval = eliminate_edge(eb); free_element(eb); }
else if ( valid_element(ec) )
{ retval = eliminate_edge(ec); free_element(ec); }
else retval = 0;
if ( retval == 0 )
{ if ( verbose_flag )
{ sprintf(msg,"pop_tri_to_edge failed on facet %s; failed to delete edge remaining after deleting facet.\n",ELNAME(f_id));
outstring(msg);
}
return 0;
}
if ( valid_element(va) ) keepv = va;
else if ( valid_element(vb) ) keepv = vb;
else if ( valid_element(vc) ) keepv = vc;
/* Identify the three downward triple lines */
trip[0] = ea = tredges[0]; trip[1] = trip[2] = NULLID;
fe = get_edge_fe(ea);
get_edge_side(ea,side);
for ( j = 0 ; j < SDIM ; j++ )
separation[j] = side[j];
for ( i = 0 ; i < 3 ; i++,fe=get_next_facet(fe) )
{ next_fe = inverse_id(get_prev_edge(fe));
while ( equal_id(get_next_facet(next_fe),get_prev_facet(next_fe)) )
next_fe = inverse_id(get_prev_edge(get_next_facet(next_fe)));
eb = get_fe_edge(next_fe);
get_edge_side(eb,side);
if ( equal_id(eb,tredges[2]) || equal_id(eb,tredges[3]) )
{ trip[1] = eb;
for ( j = 0 ; j < SDIM ; j++ )
separation[j] += side[j];
}
if ( equal_id(eb,tredges[4]) || equal_id(eb,tredges[5]) )
{ trip[2] = eb;
for ( j = 0 ; j < SDIM ; j++ )
separation[j] += side[j];
}
}
if ( !valid_id(trip[1]) || !valid_id(trip[2]) )
{ if ( verbose_flag )
{ sprintf(msg,"pop_tri_to_edge failed after deleting facet %s; didn't find triple of edges in same direction.\n",ELNAME(f_id));
outstring(msg);
}
return 0;
}
legs = 3;
/* Insert new vertex and edge */
newv = dup_vertex(keepv);
newe = new_edge(keepv,newv,NULLID);
keepx = get_coord(keepv);
newx = get_coord(newv);
for ( j = 0 ; j < SDIM ; j++ )
{ newx[j] = keepx[j] + separation[j]/12;
keepx[j] -= separation[j]/12;
}
/* Reconnect lower edge endpoints */
for ( i = 0 ; i < legs ; i++ ) /* lower triple edges */
{ facetedge_id next_fe,start_fe;
remove_vertex_edge(keepv,trip[i]);
set_edge_tailv(trip[i],newv);
fe = start_fe = get_edge_fe(trip[i]);
do /* around the multiple edge */
{
next_fe = inverse_id(get_prev_edge(fe));
for (;;)
{ /* traverse fan of edges */
edge_id eg;
if ( !equal_id(get_fe_tailv(next_fe),keepv) ) break;
if ( get_next_facet(next_fe) != get_prev_facet(next_fe) )
{ /* have reached next triple edge */
eg = get_fe_edge(next_fe);
if ( equal_id(eg,trip[0]) || equal_id(eg,trip[1])
|| equal_id(eg,trip[2]) )
{ /* all lower edges, so go back and reconnect */
next_fe = inverse_id(get_prev_edge(next_fe));
while ( !equal_id(next_fe,fe) )
{ edge_id e_id = get_fe_edge(next_fe);
remove_vertex_edge(keepv,e_id);
set_edge_tailv(e_id,newv);
next_fe = get_prev_facet(next_fe);
next_fe = inverse_id(get_prev_edge(next_fe));
}
}
else
{ /* vertical, so insert new edge above trip[i] */
facetedge_id fea = get_prev_edge(fe);
facet_id fa = get_fe_facet(fe);
facetedge_id newfe = new_facetedge(fa,newe);
facetedge_id newefe = get_edge_fe(newe);
set_next_edge(fea,newfe);
set_prev_edge(newfe,fea);
set_prev_edge(fe,newfe);
set_next_edge(newfe,fe);
if ( valid_id(newefe) )
{ set_next_facet(newfe,newefe);
set_prev_facet(newefe,newfe);
set_prev_facet(newfe,get_next_facet(newefe));
set_next_facet(get_next_facet(newefe),newfe);
}
else
{ set_edge_fe(newe,newfe);
set_next_facet(newfe,newfe);
set_prev_facet(newfe,newfe);
}
cross_cut(newfe,fe); /* triangulate */
}
break; /* done with this way out of triple edge */
}
next_fe = get_next_facet(next_fe);
next_fe = inverse_id(get_prev_edge(next_fe));
}
fe = get_next_facet(fe);
} while ( !equal_id(fe,start_fe) );
}
/* Fix up facet edge orders */
fa = get_edge_fe(newe);
fb = get_next_facet(fa);
fc = get_prev_facet(fa);
if ( equal_id(get_facet_body(get_fe_facet(fb)),
get_facet_body(inverse_id(get_fe_facet(fc)))) )
{ /* have to switch order around edge */
set_prev_facet(fa,fb);
set_prev_facet(fb,fc);
set_prev_facet(fc,fa);
set_next_facet(fa,fc);
set_next_facet(fc,fb);
set_next_facet(fb,fa);
}
if ( web.modeltype == QUADRATIC )
{ /* fix up edge midpoints */
vertex_id vv[2];
int bailcount = 0;
vv[0] = keepv; vv[1] = newv;
/* fix up edge midpoints */
for ( i = 0 ; i < 2 ; i++ )
{ edge_id start_e = get_vertex_edge(vv[i]);
edge_id ea;
ea = start_e;
do
{ new_vertex_average(get_edge_midv(ea),VOLKEEP);
ea = get_next_tail_edge(ea);
if ( bailcount++ > 1000 ) break;
} while ( !equal_id(ea,start_e));
}
}
fe_reorder(newe);
return 1;
}
/*****************************************************************************
*
* function: pop_edge_to_tri()
*
* purpose: Topology change of edge to small triangle perpendicular to it.
* Implements pop_edge_to_tri command.
*
* return: 1 for success, 0 for failure.
*/
int pop_edge_to_tri(e_id)
edge_id e_id;
{ int triples;
vertex_id tail_triples[3],head_triples[3];
vertex_id headv,tailv;
int retval;
int i,j;
conmap_t *hmap,*tmap;
int thit=0,hhit=0;
unsigned int k;
if ( (web.modeltype != LINEAR) && (web.modeltype != QUADRATIC) )
kb_error(2835,"pop_edge_to_tri only for LINEAR or QUADRATIC models.\n",
RECOVERABLE);
/* Check valences and gather info on triple edges */
if ( get_edge_valence(e_id) != 3 )
{ if ( verbose_flag )
{ sprintf(msg,
"pop_edge_to_tri fails on edge %s; it is not a triple edge.\n",
ELNAME(e_id)+1);
outstring(msg);
}
return 0;
}
tailv = get_edge_tailv(e_id);
tmap = get_v_constraint_map(tailv);
for ( k = 1 ; k <= tmap[0] ; k++ )
if ( tmap[k] & CON_HIT_BIT )
{ thit = 1;
break;
}
if ( !thit )
{ /* check for proper number of triple edges */
edge_id eb = get_next_tail_edge(e_id);
triples = 0;
while ( !equal_id(e_id,eb) )
{ int val = get_edge_valence(eb);
if ( (val < 2) || ( val > 3 ) )
{ if ( verbose_flag )
{ sprintf(msg,
"pop_edge_to_tri fails on edge %s due to edge %s having valence %d.\n",
ELNAME(e_id),ELNAME1(eb),val);
outstring(msg);
}
return 0;
}
if ( val == 3 )
{ if ( triples >= 3 )
{ if ( verbose_flag )
{ sprintf(msg,
"pop_edge_to_tri fails on edge %s due to too many triple edges at end.\n",
ELNAME(e_id)+1);
outstring(msg);
}
return 0;
}
tail_triples[triples++] = eb;
}
eb = get_next_tail_edge(eb);
}
if ( triples != 3 )
{ if ( verbose_flag )
{ sprintf(msg,
"pop_edge_to_tri fails on edge %s due to not enough triple edges at an endpoint.\n",
ELNAME(e_id));
outstring(msg);
}
return 0;
}
}
headv = get_edge_headv(e_id);
hmap = get_v_constraint_map(headv);
for ( k = 1 ; k <= hmap[0] ; k++ )
if ( hmap[k] & CON_HIT_BIT )
{ hhit = 1;
break;
}
if ( !hhit )
{ /* check for proper number of triples */
edge_id eb = get_next_head_edge(e_id);
triples = 0;
while ( !equal_id(e_id,eb) )
{ int val = get_edge_valence(eb);
if ( (val < 2) || ( val > 3 ) )
{ if ( verbose_flag )
{ sprintf(msg,
"pop_edge_to_tri fails on edge %s due to edge %s having valence %d.\n",
ELNAME(e_id),ELNAME1(eb),val);
outstring(msg);
}
return 0;
}
if ( val == 3 )
{ if ( triples >= 3 )
{ if ( verbose_flag )
{ sprintf(msg,"pop_edge_to_tri fails on edge %s due to too many triple edges at one endpoint.\n",ELNAME(e_id));
outstring(msg);
}
return 0;
}
head_triples[triples++] = inverse_id(eb);
}
eb = get_next_head_edge(eb);
}
if ( triples != 3 )
{ if ( verbose_flag )
{ sprintf(msg,"pop_edge_to_tri fails on edge %s due to not enough triple edges at one endpoint.\n",ELNAME(e_id));
outstring(msg);
}
return 0;
}
}
if ( thit && hhit )
{ if ( verbose_flag )
{ sprintf(msg,"pop_edge_to_tri fails on edge %s due to both endpoints on constraints.\n",ELNAME(e_id));
outstring(msg);
}
return 0;
}
if ( thit )
return pop_edge_to_tri_con(e_id);
if ( hhit )
return pop_edge_to_tri_con(inverse_id(e_id));
/* check for common endpoints on triples */
for ( i = 0 ; i < 3 ; i++ )
for ( j = 0 ; j < 3 ; j++ )
if ( equal_id(get_edge_headv(tail_triples[i]),
get_edge_headv(head_triples[j])) )
{ if ( verbose_flag )
{ sprintf(msg,"pop_edge_to_tri fails on edge %s due to outer triple edges with common endpoint.\n",ELNAME(e_id));
outstring(msg);
}
return 0;
}
if ( verbose_flag )
{ sprintf(msg,"pop_edge_to_tri on edge %s\n",ELNAME(e_id));
outstring(msg);
}
/* Delete the edge */
retval = eliminate_edge(e_id);
if ( retval == 0 ) return 0;
free_element(e_id);
return pop_vertex_to_tri((valid_element(headv) ? headv : tailv),tail_triples);
}
/**************************************************************************
*
* function: pop_vertex_to_tri()
*
* purpose: main work for pop_edge_to_tri and kraynik pop.
*/
int pop_vertex_to_tri(v_id,tail_triples)
vertex_id v_id;
edge_id *tail_triples;
{ int i,j;
vertex_id newv[3],keepv;
edge_id newe[3];
facet_id newf;
facetedge_id newfe[3],fe,fa,fb,fc;
edge_id ea,eb,ec,ee,head_triples[3];
/* Create new vertices, edges, and facet */
newv[0] = v_id;
newv[1] = dup_vertex(newv[0]);
newv[2] = dup_vertex(newv[0]);
newe[0] = new_edge(newv[0],newv[1],NULLID);
newe[1] = new_edge(newv[1],newv[2],NULLID);
newe[2] = new_edge(newv[2],newv[0],NULLID);
fe = get_vertex_first_facet(newv[0]);
newf = dup_facet(get_fe_facet(fe));
set_facet_body(newf,NULLID);
set_facet_body(inverse_id(newf),NULLID);
newfe[0] = new_facetedge(newf,newe[0]); set_edge_fe(newe[0],newfe[0]);
newfe[1] = new_facetedge(newf,newe[1]); set_edge_fe(newe[1],newfe[1]);
newfe[2] = new_facetedge(newf,newe[2]); set_edge_fe(newe[2],newfe[2]);
set_next_edge(newfe[0],newfe[1]);
set_next_edge(newfe[1],newfe[2]);
set_next_edge(newfe[2],newfe[0]);
set_prev_edge(newfe[0],newfe[2]);
set_prev_edge(newfe[1],newfe[0]);
set_prev_edge(newfe[2],newfe[1]);
set_facet_fe(newf,newfe[0]);
/* Reconnect things */
keepv = newv[0];
for ( i = 0 ; i < 3 ; i++ ) /* lower triple edges */
{ facetedge_id next_fe;
remove_vertex_edge(keepv,tail_triples[i]);
set_edge_tailv(tail_triples[i],newv[i]);
fe = get_edge_fe(tail_triples[i]);
for ( j = 0 ; j < 3 ; j++ ) /* around the triple edge */
{ fe = get_next_facet(fe);
next_fe = inverse_id(get_prev_edge(fe));
for (;;)
{ /* traverse fan of edges */
vertex_id vv_id;
edge_id eg,ee;
eg = get_fe_edge(next_fe);
if ( equal_element(eg,newe[0]) ) break;
if ( equal_element(eg,newe[1]) ) break;
if ( equal_element(eg,newe[2]) ) break;
vv_id = get_edge_tailv(eg);
if ( !equal_id(vv_id,keepv) && !equal_id(vv_id,newv[i]) )
{ sprintf(errmsg,
"pop_edge_to_tri bug: edge %s tail vertex is %s instead of %s.\n",
ELNAME(eg),ELNAME1(get_edge_tailv(eg)),ELNAME2(keepv));
kb_error(2834,errmsg,RECOVERABLE);
break;
}
if ( get_next_facet(next_fe) != get_prev_facet(next_fe) )
{ /* have reached next triple edge */
if ( equal_id(eg,tail_triples[(i+2)%3]) ) break;
else if ( equal_id(eg,tail_triples[(i+1)%3]) )
{ /* all lower edges, so go back and split out to triangle edge */
facetedge_id feb = inverse_id(get_prev_edge(fe));
facetedge_id fea = get_prev_edge(fe);
facet_id fa = get_fe_facet(fe);
facetedge_id newfe = new_facetedge(fa,inverse_id(newe[i]));
facetedge_id newefe = get_edge_fe(inverse_id(newe[i]));
while ( !equal_id(feb,next_fe) )
{ ee = get_fe_edge(feb);
remove_vertex_edge(keepv,ee);
set_edge_tailv(ee,newv[(i+1)%3]);
feb = get_next_facet(feb);
feb = inverse_id(get_prev_edge(feb));
}
set_next_edge(fea,newfe);
set_prev_edge(newfe,fea);
set_prev_edge(fe,newfe);
set_next_edge(newfe,fe);
set_next_facet(newfe,newefe);
set_prev_facet(newefe,newfe);
set_next_facet(newefe,newfe);
set_prev_facet(newfe,newefe);
cross_cut(newfe,fe); /* triangulate */
}
else /* hit one of the head_triples */
{ /* vertical wall, so reconnect */
head_triples[i] = eg;
next_fe = inverse_id(get_prev_edge(next_fe));
while ( !equal_id(next_fe,fe) )
{ edge_id ee = get_fe_edge(next_fe);
remove_vertex_edge(keepv,ee);
set_edge_tailv(ee,newv[i]);
next_fe = get_prev_facet(next_fe);
next_fe = inverse_id(get_prev_edge(next_fe));
}
}
break; /* done with this way out of triple edge */
}
next_fe = get_next_facet(next_fe);
next_fe = inverse_id(get_prev_edge(next_fe));
}
}
}
/* Now go around head end and reconnect, head_triples having been
put in proper correspondence above */
for ( i = 0 ; i < 3 ; i++ ) /* upper triple edges */
{ facetedge_id next_fe;
remove_vertex_edge(keepv,head_triples[i]);
set_edge_tailv(head_triples[i],newv[i]);
fe = get_edge_fe(head_triples[i]);
for ( j = 0 ; j < 3 ; j++ ) /* around the triple edge */
{ fe = get_next_facet(fe);
next_fe = inverse_id(get_prev_edge(fe));
for (;;)
{ /* traverse fan of edges */
edge_id eg;
if ( !equal_id(get_fe_tailv(next_fe),keepv) ) break;
eg = get_fe_edge(next_fe);
if ( get_next_facet(next_fe) != get_prev_facet(next_fe) )
{ /* have reached next triple edge */
if ( equal_id(eg,head_triples[(i+2)%3]) ) break;
if ( equal_element(eg,newe[0]) ) break;
if ( equal_element(eg,newe[1]) ) break;
if ( equal_element(eg,newe[2]) ) break;
else if ( equal_id(eg,head_triples[(i+1)%3]) )
{ /* all upper edges, so go back and split out to triangle edge */
facetedge_id feb = inverse_id(get_prev_edge(fe));
facetedge_id fea = get_prev_edge(fe);
facet_id fa = get_fe_facet(fe);
facetedge_id newfe = new_facetedge(inverse_id(fa),newe[i]);
facetedge_id newefe = get_edge_fe(newe[i]);
while ( !equal_id(feb,next_fe) )
{ ee = get_fe_edge(feb);
remove_vertex_edge(keepv,ee);
set_edge_tailv(ee,newv[(i+1)%3]);
feb = get_next_facet(feb);
feb = inverse_id(get_prev_edge(feb));
}
set_next_edge(fea,inverse_id(newfe));
set_prev_edge(inverse_id(newfe),fea);
set_prev_edge(fe,inverse_id(newfe));
set_next_edge(inverse_id(newfe),fe);
set_next_facet(newfe,newefe);
set_prev_facet(newefe,newfe);
set_prev_facet(newfe,get_next_facet(newefe));
set_next_facet(get_next_facet(newefe),newfe);
cross_cut(inverse_id(newfe),fe); /* triangulate */
}
else /* hit one of the head_triples */
{ /* vertical wall, but those already reconnected */
}
break; /* done with this way out of triple edge */
}
next_fe = get_next_facet(next_fe);
next_fe = inverse_id(get_prev_edge(next_fe));
}
}
}
/* Spread new vertices */
for ( i = 0 ; i < 3 ; i++ ) /* the vertices */
{ REAL *x,side1[MAXCOORD],side2[MAXCOORD];
x = get_coord(newv[i]);
get_edge_side(tail_triples[i],side1);
get_edge_side(head_triples[i],side2);
for ( j = 0 ; j < SDIM ; j++ )
x[j] += (side1[j]+side2[j])/6;
}
/* Fix up facet edge orders */
for ( i = 0 ; i < 3 ; i++ )
{ facetedge_id next_fe;
int count;
vertex_id base_v;
fa = newfe[i];
fb = get_next_facet(fa);
fc = get_prev_facet(fa);
ea = get_fe_edge(fa);
eb = get_fe_edge(inverse_id(get_prev_edge(fa)));
base_v = get_edge_tailv(ea);
next_fe = inverse_id(get_prev_edge(fb));
for(count=0;count < 10000 ;count++)
{ ec = get_fe_edge(next_fe);
if ( !equal_id(get_edge_tailv(ec),base_v) )
kb_error(2833,"pop_tri_to_edge failure.\n",RECOVERABLE);
if ( equal_id(ec,ea) )
break; /* ok */
if ( equal_id(ec,eb) )
{ /* have to switch order around edge */
set_prev_facet(fa,fb);
set_prev_facet(fb,fc);
set_prev_facet(fc,fa);
set_next_facet(fa,fc);
set_next_facet(fc,fb);
set_next_facet(fb,fa);
break;
}
next_fe = inverse_id(get_prev_edge(get_prev_facet(next_fe)));
}
if ( count >= 10000 )
{ sprintf(errmsg,"Internal error after pop_vertex_to_tri edge %s, bad topology around vertex %s.\n",ELNAME(v_id),ELNAME1(get_edge_tailv(ea)));
kb_error(2832,errmsg,RECOVERABLE);
}
}
/* Fix up bodies on new facet */
fe = newfe[0];
set_facet_body(newf,
get_facet_body(inverse_id(get_fe_facet(get_prev_facet(fe)))));
set_facet_body(inverse_id(newf),
get_facet_body(get_fe_facet(get_next_facet(fe))));
if ( web.modeltype == QUADRATIC )
{ /* fix up edge midpoints */
int bailcount = 0;
for ( i = 0 ; i < 3 ; i++ )
{ edge_id start_e = get_vertex_edge(newv[i]);
edge_id ea;
ea = start_e;
do
{ new_vertex_average(get_edge_midv(ea),VOLKEEP);
ea = get_next_tail_edge(ea);
if ( bailcount++ > 1000 ) break;
} while ( !equal_id(ea,start_e));
}
}
return 1;
} /* end pop_edge_to_tri */
/**************************************************************************
*
* function: pop_vertex_to_quad()
*
* purpose: main work for pop_cubecone.
*/
int pop_vertex_to_quad(v_id,tail_triples)
vertex_id v_id;
edge_id *tail_triples;
{ int i,j;
vertex_id newv[4],keepv;
edge_id newe[4];
facet_id newf;
facetedge_id newfe[4],fe,fa,fb,fc;
edge_id ea,eb,ec,ee,head_triples[4];
/* Create new vertices, edges, and facet */
newv[0] = v_id;
newv[1] = dup_vertex(newv[0]);
newv[2] = dup_vertex(newv[0]);
newv[3] = dup_vertex(newv[0]);
newe[0] = new_edge(newv[0],newv[1],NULLID);
newe[1] = new_edge(newv[1],newv[2],NULLID);
newe[2] = new_edge(newv[2],newv[3],NULLID);
newe[3] = new_edge(newv[3],newv[0],NULLID);
fe = get_vertex_first_facet(newv[0]);
newf = dup_facet(get_fe_facet(fe));
set_facet_body(newf,NULLID);
set_facet_body(inverse_id(newf),NULLID);
newfe[0] = new_facetedge(newf,newe[0]); set_edge_fe(newe[0],newfe[0]);
newfe[1] = new_facetedge(newf,newe[1]); set_edge_fe(newe[1],newfe[1]);
newfe[2] = new_facetedge(newf,newe[2]); set_edge_fe(newe[2],newfe[2]);
newfe[3] = new_facetedge(newf,newe[3]); set_edge_fe(newe[3],newfe[3]);
set_next_edge(newfe[0],newfe[1]);
set_next_edge(newfe[1],newfe[2]);
set_next_edge(newfe[2],newfe[3]);
set_next_edge(newfe[3],newfe[0]);
set_prev_edge(newfe[0],newfe[3]);
set_prev_edge(newfe[1],newfe[0]);
set_prev_edge(newfe[2],newfe[1]);
set_prev_edge(newfe[3],newfe[2]);
set_facet_fe(newf,newfe[0]);
/* Reconnect things */
keepv = newv[0];
for ( i = 0 ; i < 4 ; i++ ) /* lower triple edges */
{ facetedge_id next_fe;
remove_vertex_edge(keepv,tail_triples[i]);
set_edge_tailv(tail_triples[i],newv[i]);
fe = get_edge_fe(tail_triples[i]);
for ( j = 0 ; j < 3 ; j++ ) /* around the triple edge */
{ fe = get_next_facet(fe);
next_fe = inverse_id(get_prev_edge(fe));
for (;;)
{ /* traverse fan of edges */
vertex_id vv_id;
edge_id eg,ee;
eg = get_fe_edge(next_fe);
if ( equal_element(eg,newe[0]) ) break;
if ( equal_element(eg,newe[1]) ) break;
if ( equal_element(eg,newe[2]) ) break;
if ( equal_element(eg,newe[3]) ) break;
vv_id = get_edge_tailv(eg);
if ( !equal_id(vv_id,keepv) && !equal_id(vv_id,newv[i]) )
{ sprintf(errmsg,
"pop_vertex_to_quad bug: edge %s tail vertex is %s instead of %s.\n",
ELNAME(eg),ELNAME1(get_edge_tailv(eg)),ELNAME2(keepv));
kb_error(3930,errmsg,RECOVERABLE);
break;
}
if ( get_next_facet(next_fe) != get_prev_facet(next_fe) )
{ /* have reached next triple edge */
if ( equal_id(eg,tail_triples[(i+3)%4]) ) break;
else if ( equal_id(eg,tail_triples[(i+1)%4]) )
{ /* all lower edges, so go back and split out to triangle edge */
facetedge_id feb = inverse_id(get_prev_edge(fe));
facetedge_id fea = get_prev_edge(fe);
facet_id fa = get_fe_facet(fe);
facetedge_id newfe = new_facetedge(fa,inverse_id(newe[i]));
facetedge_id newefe = get_edge_fe(inverse_id(newe[i]));
while ( !equal_id(feb,next_fe) )
{ ee = get_fe_edge(feb);
remove_vertex_edge(keepv,ee);
set_edge_tailv(ee,newv[(i+1)%4]);
feb = get_next_facet(feb);
feb = inverse_id(get_prev_edge(feb));
}
set_next_edge(fea,newfe);
set_prev_edge(newfe,fea);
set_prev_edge(fe,newfe);
set_next_edge(newfe,fe);
set_next_facet(newfe,newefe);
set_prev_facet(newefe,newfe);
set_next_facet(newefe,newfe);
set_prev_facet(newfe,newefe);
cross_cut(newfe,fe); /* triangulate */
}
else /* hit one of the head_triples */
{ /* vertical wall, so reconnect */
head_triples[i] = eg;
next_fe = inverse_id(get_prev_edge(next_fe));
while ( !equal_id(next_fe,fe) )
{ edge_id ee = get_fe_edge(next_fe);
remove_vertex_edge(keepv,ee);
set_edge_tailv(ee,newv[i]);
next_fe = get_prev_facet(next_fe);
next_fe = inverse_id(get_prev_edge(next_fe));
}
}
break; /* done with this way out of triple edge */
}
next_fe = get_next_facet(next_fe);
next_fe = inverse_id(get_prev_edge(next_fe));
}
}
}
/* Now go around head end and reconnect, head_triples having been
put in proper correspondence above */
for ( i = 0 ; i < 4 ; i++ ) /* upper triple edges */
{ facetedge_id next_fe;
remove_vertex_edge(keepv,head_triples[i]);
set_edge_tailv(head_triples[i],newv[i]);
fe = get_edge_fe(head_triples[i]);
for ( j = 0 ; j < 3 ; j++ ) /* around the triple edge */
{ fe = get_next_facet(fe);
next_fe = inverse_id(get_prev_edge(fe));
for (;;)
{ /* traverse fan of edges */
edge_id eg;
if ( !equal_id(get_fe_tailv(next_fe),keepv) ) break;
eg = get_fe_edge(next_fe);
if ( get_next_facet(next_fe) != get_prev_facet(next_fe) )
{ /* have reached next triple edge */
if ( equal_id(eg,head_triples[(i+3)%4]) ) break;
if ( equal_element(eg,newe[0]) ) break;
if ( equal_element(eg,newe[1]) ) break;
if ( equal_element(eg,newe[2]) ) break;
if ( equal_element(eg,newe[3]) ) break;
else if ( equal_id(eg,head_triples[(i+1)%4]) )
{ /* all upper edges, so go back and split out to triangle edge */
facetedge_id feb = inverse_id(get_prev_edge(fe));
facetedge_id fea = get_prev_edge(fe);
facet_id fa = get_fe_facet(fe);
facetedge_id newfe = new_facetedge(inverse_id(fa),newe[i]);
facetedge_id newefe = get_edge_fe(newe[i]);
while ( !equal_id(feb,next_fe) )
{ ee = get_fe_edge(feb);
remove_vertex_edge(keepv,ee);
set_edge_tailv(ee,newv[(i+1)%4]);
feb = get_next_facet(feb);
feb = inverse_id(get_prev_edge(feb));
}
set_next_edge(fea,inverse_id(newfe));
set_prev_edge(inverse_id(newfe),fea);
set_prev_edge(fe,inverse_id(newfe));
set_next_edge(inverse_id(newfe),fe);
set_next_facet(newfe,newefe);
set_prev_facet(newefe,newfe);
set_prev_facet(newfe,get_next_facet(newefe));
set_next_facet(get_next_facet(newefe),newfe);
cross_cut(inverse_id(newfe),fe); /* triangulate */
}
else /* hit one of the head_triples */
{ /* vertical wall, but those already reconnected */
}
break; /* done with this way out of triple edge */
}
next_fe = get_next_facet(next_fe);
next_fe = inverse_id(get_prev_edge(next_fe));
}
}
}
/* Spread new vertices */
for ( i = 0 ; i < 4 ; i++ ) /* the vertices */
{ REAL *x,side1[MAXCOORD],side2[MAXCOORD];
x = get_coord(newv[i]);
get_edge_side(tail_triples[i],side1);
get_edge_side(head_triples[i],side2);
for ( j = 0 ; j < SDIM ; j++ )
x[j] += (side1[j]+side2[j])/6;
}
/* Fix up facet edge orders */
for ( i = 0 ; i < 4 ; i++ )
{ facetedge_id next_fe;
int count;
vertex_id base_v;
fa = newfe[i];
fb = get_next_facet(fa);
fc = get_prev_facet(fa);
ea = get_fe_edge(fa);
eb = get_fe_edge(inverse_id(get_prev_edge(fa)));
base_v = get_edge_tailv(ea);
next_fe = inverse_id(get_prev_edge(fb));
for(count=0;count < 10000 ;count++)
{ ec = get_fe_edge(next_fe);
if ( !equal_id(get_edge_tailv(ec),base_v) )
kb_error(4833,"pop_vertex_to_quad failure.\n",RECOVERABLE);
if ( equal_id(ec,ea) )
break; /* ok */
if ( equal_id(ec,eb) )
{ /* have to switch order around edge */
set_prev_facet(fa,fb);
set_prev_facet(fb,fc);
set_prev_facet(fc,fa);
set_next_facet(fa,fc);
set_next_facet(fc,fb);
set_next_facet(fb,fa);
break;
}
next_fe = inverse_id(get_prev_edge(get_prev_facet(next_fe)));
}
if ( count >= 10000 )
{ sprintf(errmsg,"Internal error after pop_vertex_to_quad edge %s, bad topology around vertex %s.\n",ELNAME(v_id),ELNAME1(get_edge_tailv(ea)));
kb_error(4832,errmsg,RECOVERABLE);
}
}
/* Fix up bodies on new facet */
fe = newfe[0];
set_facet_body(newf,
get_facet_body(inverse_id(get_fe_facet(get_prev_facet(fe)))));
set_facet_body(inverse_id(newf),
get_facet_body(get_fe_facet(get_next_facet(fe))));
if ( web.modeltype == QUADRATIC )
{ /* fix up edge midpoints */
int bailcount = 0;
for ( i = 0 ; i < 4 ; i++ )
{ edge_id start_e = get_vertex_edge(newv[i]);
edge_id ea;
ea = start_e;
do
{ new_vertex_average(get_edge_midv(ea),VOLKEEP);
ea = get_next_tail_edge(ea);
if ( bailcount++ > 1000 ) break;
} while ( !equal_id(ea,start_e));
}
}
/* divide central square */
cross_cut(newfe[0],newfe[1]);
return 1;
} /* end pop_vertex_to_quad */
/*****************************************************************************
*
* function: pop_quad_to_quad()
*
* purpose: Topology change of narrow quadrilateral to quad perpendicular to it.
* Implements pop_quad_to_quad command.
*
* return: 1 for success, 0 for failure.
*/
int pop_quad_to_quad(f_id)
facet_id f_id; /* one facet of the quadrilateral */
{ facetedge_id fe,next_fe,start_fe,quad_triples[4],newfe[4],fea,keepfe;
edge_id e_id,ee_id,eee_id,other_triples[4][2],ea,eb,ec,keepe,newe[4];
vertex_id newv[4];
facet_id newf,fa,fb,fc;
body_id b_id;
int i,j,k,ii,jj;
REAL len[4];
REAL sides[4][2][MAXCOORD];
REAL *x[4];
#define MAXQF 100
facet_id quadfacets[MAXQF];
int qfcount;
if ( (web.modeltype != LINEAR) && (web.modeltype != QUADRATIC) )
kb_error(2836,"pop_quad_to_quad only for LINEAR or QUADRATIC models.\n",
RECOVERABLE);
/* quad could be four facets or two, or more */
/* Check geometry and gather info about triple edges */
/* find triple edge on original facet */
fe = get_facet_fe(f_id);
for ( i = 0 ; i < 3 ; i++ )
{ edge_id e_id = get_fe_edge(fe);
if ( get_edge_valence(e_id) == 3 ) break;
fe = get_next_edge(fe);
}
if ( i == 3 ) /* couldn't find a triple edge */
{ if ( verbose_flag )
{ sprintf(msg,"pop_quad_to_quad fails on facet %s since it doesn't have a triple edge.\n",ELNAME(f_id));
outstring(msg);
}
return 0;
}
/* march around inner quad */
start_fe = fe;
for ( i = 0 ; i < 4 ; i++ )
{
for(;;) /* seek next triple */
{ fe = inverse_id(get_prev_edge(fe));
if ( equal_id(fe,get_next_facet(fe)) ) /* valence 1 edge */
{ if ( verbose_flag )
{ sprintf(msg,"pop_quad_to_quad fails on facet %s; edge %s has valence 1.\n",ELNAME(f_id),ELNAME1(get_fe_edge(fe)));
outstring(msg);
}
return 0;
}
if ( !equal_id(get_next_facet(fe),get_prev_facet(fe)) )
break; /* found triple */
fe = get_next_facet(fe);
}
/* now have next triple */
e_id = get_fe_edge(fe);
if ( get_edge_valence(e_id) != 3 )
{ if ( verbose_flag )
{ sprintf(msg,"pop_quad_to_quad fails on facet %s; edge %s valence too high.\n",ELNAME(f_id),ELNAME1(e_id));
outstring(msg);
}
return 0;
}
quad_triples[i] = fe;
fe = inverse_id(fe); /* get ready for next triple line search */
}
if ( !equal_id(start_fe,fe) )
{ if ( verbose_flag )
{ sprintf(msg,"pop_quad_to_quad fails on facet %s; didn't find quadrilateral of triple edges.\n",ELNAME(f_id));
outstring(msg);
}
return 0;
}
/* Find shorter pair of opposite edges, and swap if necessary
so quad_triples[1,3] has short edges */
for ( i = 0 ; i < 4 ; i++ )
{ e_id = get_fe_edge(quad_triples[i]);
calc_edge(e_id);
len[i] = get_edge_length(e_id);
}
if ( (len[0]+len[2]) < (len[1]+len[3]) )
{ facetedge_id temp_fe = quad_triples[0];
quad_triples[0] = quad_triples[1];
quad_triples[1] = quad_triples[2];
quad_triples[2] = quad_triples[3];
quad_triples[3] = temp_fe;
}
/* Find the other triple lines at each corner */
for ( i = 0 ; i < 4 ; i++ )
{ edge_id ee_id;
int val;
e_id = get_fe_edge(quad_triples[i]);
ee_id = e_id;
j = 0;
do
{ ee_id = get_next_tail_edge(ee_id);
val = get_edge_valence(ee_id);
if ( (val < 2) || (val > 3) )
{ if ( verbose_flag )
{ sprintf(msg,
"pop_quad_to_quad fails on facet %s since edge %s has valence %d.\n",
ELNAME(f_id),ELNAME1(ee_id),val);
outstring(msg);
}
return 0;
}
if ( val == 3 )
{ if ( equal_element(ee_id,e_id) ) continue;
if ( equal_element(ee_id,get_fe_edge(quad_triples[(i+3)%4])) )
continue;
if ( j >= 2 )
{ if ( verbose_flag )
{ sprintf(msg,"pop_quad_to_quad fails on facet %s; too many triple edges on vertex %s.\n",ELNAME(f_id),ELNAME1(get_edge_tailv(ee_id)));
outstring(msg);
}
return 0;
}
other_triples[i][j++] = ee_id;
}
} while ( !equal_id(e_id,ee_id));
if ( j != 2 )
{ if ( verbose_flag )
{ sprintf(msg,"pop_quad_to_quad fails on facet %s since vertex %s doesn't have enough triple edges.\n",ELNAME(f_id),ELNAME1(get_edge_tailv(e_id)));
outstring(msg);
}
return 0;
}
}
/* check outer triples for common endpoints, due to triangular
* prisms and pyramids.
*/
for ( i = 0 ; i < 4 ; i++ )
for ( j = 0 ; j < 2 ; j++ )
for ( ii = i ; ii < 4 ; ii++ )
for ( jj = 0 ; jj < 2 ; jj++ )
{ if ( (ii == i) && (jj == j) ) continue;
if ( equal_id(get_edge_headv(other_triples[i][j]),
get_edge_headv(other_triples[ii][jj])) )
{ sprintf(msg,"Pop_quad_to_quad fails on facet %s\n",ELNAME(f_id));
sprintf(msg+strlen(msg),
" since triple edges %s and %s have common far endpoint.\n",
ELNAME(other_triples[i][j]),ELNAME1(other_triples[ii][jj]));
strcat(msg," Probably a face of a pyramid or triangular prism.\n");
outstring(msg);
return 0;
}
}
if ( verbose_flag )
{ sprintf(msg,"pop_quad_to_quad on facet %s\n",ELNAME(f_id));
outstring(msg);
}
ea = get_fe_edge(quad_triples[0]); /* for identifying kept edge */
eb = get_fe_edge(quad_triples[2]);
/* use old facet to get attributes for new before deleting old */
/* newf = new_facet(); */
newf = dup_facet(f_id);
set_facet_body(newf,NULLID);
set_facet_body(inverse_id(newf),NULLID);
/* get list of the quadrilateral's facets, in case quad is subdivided
too much for simple edge deletion to take care of
*/
quadfacets[0] = f_id;
qfcount = 1;
for ( i = 0 ; i < qfcount ; i++ )
{ fa = quadfacets[i];
fea = get_facet_fe(fa);
for ( j = 0 ; j < 3 ; j++, fea = get_next_edge(fea) )
{ if ( equal_id(get_next_facet(fea),get_prev_facet(fea)) )
{ /* add neighbor facet to list if not already there */
fb = get_fe_facet(get_next_facet(fea));
for ( k = 0 ; k < qfcount ; k++ )
{ if ( equal_element(fb,quadfacets[k]) )
break;
}
if ( k == qfcount ) /* not found, so add to list */
{ if ( qfcount >= MAXQF )
{ kb_error(2840,"pop_quad_to_quad: over 100 facets in quadrilateral.\n", RECOVERABLE);
}
quadfacets[qfcount++] = fb;
}
}
}
}
/* Delete original quadrilateral by deleting the short edges */
keepfe = get_next_facet(quad_triples[0]);
e_id = get_fe_edge(quad_triples[1]);
eliminate_edge(e_id);
free_element(e_id);
e_id = get_fe_edge(quad_triples[3]);
eliminate_edge(e_id);
free_element(e_id);
/* now delete any leftover quadrilateral facets */
for ( i = 0 ; i < qfcount ; i++ )
if ( valid_element(quadfacets[i]) )
eliminate_facet(quadfacets[i]);
/* make sure all the triple lines are left */
for ( i = 0 ; i < 4 ; i++ )
for ( j = 0 ; j < 2 ; j++ )
if ( !valid_element(other_triples[i][j]) )
{ sprintf(errmsg,
"Unanticipated geometry after eliminating quad for facet %s.\n",
ELNAME(f_id));
strcat(errmsg,"New quad not created.\n");
kb_error(2828,errmsg,WARNING);
}
/* Identify the remaining edge */
keepe = get_fe_edge(keepfe);
/* Create new quad */
newv[0] = get_edge_tailv(keepe);
newv[1] = get_edge_headv(keepe);
newv[2] = dup_vertex(newv[1]);
newv[3] = dup_vertex(newv[0]);
newe[0] = keepe;
newe[1] = dup_edge(keepe);
set_edge_tailv(newe[1],newv[1]);
set_edge_headv(newe[1],newv[2]);
newe[2] = dup_edge(keepe);
set_edge_tailv(newe[2],newv[2]);
set_edge_headv(newe[2],newv[3]);
newe[3] = dup_edge(keepe);
set_edge_tailv(newe[3],newv[3]);
set_edge_headv(newe[3],newv[0]);
if ( web.symmetry_flag )
{ set_edge_wrap(newe[1],0);
set_edge_wrap(newe[2],(*sym_inverse)(get_edge_wrap(newe[0])));
set_edge_wrap(newe[3],0);
}
for ( i = 0 ; i < 4 ; i++ )
{ newfe[i] = new_facetedge(newf,newe[i]);
set_next_facet(newfe[i],newfe[i]);
set_prev_facet(newfe[i],newfe[i]);
set_edge_fe(newe[i],newfe[i]);
}
set_facet_fe(newf,newfe[0]);
for ( i = 0 ; i < 4 ; i++ )
{ set_next_edge(newfe[i],newfe[(i+1)%4]);
set_prev_edge(newfe[i],newfe[(i+3)%4]);
}
cross_cut(newfe[0],newfe[1]);
/* Connect in with old stuff */
/* start with first corner */
e_id = other_triples[0][0];
fe = get_edge_fe(e_id);
for ( k = 0 ; k < 3 ; k++ )
{ /* traverse fan in all three directions */
fe = get_next_facet(fe);
next_fe = inverse_id(get_prev_edge(fe));
for (;;)
{ if ( !equal_id(get_next_facet(next_fe),get_prev_facet(next_fe)) )
{ /* have found next triple edge */
ee_id = get_fe_edge(next_fe);
if ( equal_element(ee_id,keepe) )
{ /* everything already ok, but adjust facetedges */
fea = newfe[0];
set_next_facet(next_fe,fea);
set_prev_facet(fea,next_fe);
set_prev_facet(next_fe,fea);
set_next_facet(fea,next_fe);
/* and line up next corner */
for(;;)
{ next_fe = get_next_edge(next_fe);
if ( !equal_id(get_next_facet(next_fe),get_prev_facet(next_fe)) )
{ /* have found next triple edge */
eee_id = get_fe_edge(next_fe);
if ( equal_element(eee_id,other_triples[1][0]) )
{ /* all ok */
}
else if ( equal_element(eee_id,other_triples[1][1]) )
{ /* swap */
edge_id tempe = other_triples[1][0];
other_triples[1][0] = other_triples[1][1];
other_triples[1][1] = tempe;
}
break;
}
next_fe = inverse_id(get_next_facet(next_fe));
}
}
else if ( equal_id(ee_id,other_triples[0][1]) )
{ /* spread out with new edge */
facetedge_id feb = inverse_id(get_prev_edge(fe));
facetedge_id fea = get_prev_edge(fe);
facet_id fa = get_fe_facet(fe);
facetedge_id newfe = new_facetedge(fa,newe[3]);
facetedge_id newefe = get_edge_fe(newe[3]);
while ( !equal_id(feb,next_fe) )
{ eee_id = get_fe_edge(feb);
remove_vertex_edge(newv[0],eee_id);
set_edge_tailv(eee_id,newv[3]);
feb = get_next_facet(feb);
feb = inverse_id(get_prev_edge(feb));
}
set_next_edge(fea,newfe);
set_prev_edge(newfe,fea);
set_prev_edge(fe,newfe);
set_next_edge(newfe,fe);
set_next_facet(newfe,newefe);
set_prev_facet(newefe,newfe);
set_next_facet(newefe,newfe);
set_prev_facet(newfe,newefe);
cross_cut(newfe,fe);
}
else if ( equal_id(ee_id,other_triples[3][0]) )
{ /* everything ok */
}
else if ( equal_id(ee_id,other_triples[3][1]) )
{ /* swap */
edge_id tempe = other_triples[3][0];
other_triples[3][0] = other_triples[3][1];
other_triples[3][1] = tempe;
}
else /* shouldn't get here */
kb_error(2820,"Aborted pop_quad_to_quad halfway through.\n",
RECOVERABLE);
break;
}
next_fe = get_next_facet(next_fe);
next_fe = inverse_id(get_prev_edge(next_fe));
}
}
/* other triple out of first corner */
e_id = other_triples[3][0];
fe = get_edge_fe(e_id);
for ( k = 0 ; k < 3 ; k++ )
{ /* traverse fan in all three directions */
fe = get_next_facet(fe);
next_fe = inverse_id(get_prev_edge(fe));
for (;;)
{ if ( !equal_id(get_next_facet(next_fe),get_prev_facet(next_fe)) )
{ /* have found next triple edge */
ee_id = get_fe_edge(next_fe);
if ( equal_element(ee_id,keepe) )
{ /* everything already ok, adjust facetedges */
fea = newfe[0];
set_next_facet(next_fe,fea);
set_prev_facet(fea,next_fe);
set_prev_facet(next_fe,get_next_facet(fea));
set_next_facet(get_next_facet(fea),next_fe);
/* and line up next corner */
for(;;)
{ next_fe = get_next_edge(next_fe);
if ( !equal_id(get_next_facet(next_fe),get_prev_facet(next_fe)) )
{ /* have found next triple edge */
eee_id = get_fe_edge(next_fe);
if ( equal_element(eee_id,other_triples[2][0]) )
{ /* all ok */
}
else if ( equal_element(eee_id,other_triples[2][1]) )
{ /* swap */
edge_id tempe = other_triples[2][0];
other_triples[2][0] = other_triples[2][1];
other_triples[2][1] = tempe;
}
break;
}
next_fe = inverse_id(get_next_facet(next_fe));
}
}
else if ( equal_id(ee_id,other_triples[3][1]) )
{ /* spread out with new edge */
facetedge_id feb = inverse_id(get_prev_edge(fe));
facetedge_id fea = get_prev_edge(fe);
facet_id fa = get_fe_facet(fe);
facetedge_id newfe = new_facetedge(fa,newe[3]);
facetedge_id newefe = get_edge_fe(newe[3]);
while ( !equal_id(feb,next_fe) )
{ eee_id = get_fe_edge(feb);
remove_vertex_edge(newv[0],eee_id);
set_edge_tailv(eee_id,newv[3]);
feb = get_next_facet(feb);
feb = inverse_id(get_prev_edge(feb));
}
set_next_edge(fea,newfe);
set_prev_edge(newfe,fea);
set_prev_edge(fe,newfe);
set_next_edge(newfe,fe);
set_next_facet(newfe,newefe);
set_prev_facet(newefe,newfe);
set_next_facet(get_next_facet(newefe),newfe);
set_prev_facet(newfe,get_next_facet(newefe));
cross_cut(newfe,fe);
}
else if ( equal_id(ee_id,other_triples[0][0]) )
{ /* everything ok */
}
else /* shouldn't get here */
kb_error(2821,"Aborted pop_quad_to_quad halfway through.\n",
RECOVERABLE);
break;
}
next_fe = get_next_facet(next_fe);
next_fe = inverse_id(get_prev_edge(next_fe));
}
}
/* another corner, at end of short edge from previous */
e_id = other_triples[0][1];
fe = get_edge_fe(e_id);
for ( k = 0 ; k < 3 ; k++ )
{ /* traverse fan in all three directions */
fe = get_next_facet(fe);
next_fe = fe;
for (;;)
{ ee_id = get_fe_edge(next_fe);
if ( !equal_id(get_edge_tailv(ee_id),newv[3]) )
{ remove_vertex_edge(newv[0],ee_id);
set_edge_tailv(ee_id,newv[3]);
}
next_fe = inverse_id(get_prev_edge(next_fe));
if ( !equal_id(get_next_facet(next_fe),get_prev_facet(next_fe)) )
{ /* have found next triple edge */
ee_id = get_fe_edge(next_fe);
if ( equal_element(ee_id,newe[0]) )
{ /* move fe to new edge */
set_fe_edge(next_fe,inverse_id(newe[2]));
fea = inverse_id(newfe[2]);
set_next_facet(next_fe,fea);
set_prev_facet(fea,next_fe);
set_prev_facet(next_fe,fea);
set_next_facet(fea,next_fe);
}
else if ( equal_element(ee_id,newe[3]) )
{ /* all ok */
}
else if ( equal_id(ee_id,other_triples[3][1]) )
{ /* everything ok */
}
else /* shouldn't get here */
kb_error(2822,"Aborted pop_quad_to_quad halfway through.\n",
WARNING);
break;
}
next_fe = get_next_facet(next_fe);
}
}
/* other part of same corner, at end of short edge from previous */
e_id = other_triples[3][1];
fe = get_edge_fe(e_id);
for ( k = 0 ; k < 3 ; k++ )
{ /* traverse fan in all three directions */
fe = get_next_facet(fe);
next_fe = fe;
for (;;)
{ ee_id = get_fe_edge(next_fe);
if ( !equal_id(get_edge_tailv(ee_id),newv[3]) )
{ remove_vertex_edge(newv[0],ee_id);
set_edge_tailv(ee_id,newv[3]);
}
next_fe = inverse_id(get_prev_edge(next_fe));
if ( !equal_id(get_next_facet(next_fe),get_prev_facet(next_fe)) )
{ /* have found next triple edge */
ee_id = get_fe_edge(next_fe);
if ( equal_element(ee_id,newe[0]) )
{ /* move fe to new edge */
set_fe_edge(next_fe,inverse_id(newe[2]));
fea = inverse_id(newfe[2]);
set_next_facet(next_fe,get_prev_facet(fea));
set_prev_facet(get_prev_facet(fea),next_fe);
set_prev_facet(next_fe,fea);
set_next_facet(fea,next_fe);
}
else if ( equal_id(ee_id,other_triples[0][1]) )
{ /* all ok */
}
else if ( equal_element(ee_id,newe[3]) )
{ /* everything ok */
}
else /* shouldn't get here */
kb_error(2823,"Aborted pop_quad_to_quad halfway through.\n",
WARNING);
break;
}
next_fe = get_next_facet(next_fe);
}
}
/* corner at other end of long edge from first corner */
e_id = other_triples[1][0];
fe = get_edge_fe(e_id);
for ( k = 0 ; k < 3 ; k++ )
{ /* traverse fan in all three directions */
fe = get_next_facet(fe);
next_fe = inverse_id(get_prev_edge(fe));
for (;;)
{ if ( !equal_id(get_next_facet(next_fe),get_prev_facet(next_fe)) )
{ /* have found next triple edge */
ee_id = get_fe_edge(next_fe);
if ( equal_element(ee_id,keepe) )
{ /* everything already ok, but adjust facetedges */
}
else if ( equal_id(ee_id,other_triples[1][1]) )
{ /* spread out with new edge */
facetedge_id feb = inverse_id(get_prev_edge(fe));
facetedge_id fea = get_prev_edge(fe);
facet_id fa = get_fe_facet(fe);
facetedge_id newfe = new_facetedge(fa,inverse_id(newe[1]));
facetedge_id newefe = get_edge_fe(inverse_id(newe[1]));
while ( !equal_id(feb,next_fe) )
{ eee_id = get_fe_edge(feb);
remove_vertex_edge(newv[1],eee_id);
set_edge_tailv(eee_id,newv[2]);
feb = get_next_facet(feb);
feb = inverse_id(get_prev_edge(feb));
}
set_next_edge(fea,newfe);
set_prev_edge(newfe,fea);
set_prev_edge(fe,newfe);
set_next_edge(newfe,fe);
set_next_facet(newfe,newefe);
set_prev_facet(newefe,newfe);
set_next_facet(newefe,newfe);
set_prev_facet(newfe,newefe);
cross_cut(newfe,fe);
}
else if ( equal_id(ee_id,other_triples[2][0]) )
{ /* everything ok */
}
else /* shouldn't get here */
kb_error(2824,"Aborted pop_quad_to_quad halfway through.\n",
WARNING);
break;
}
next_fe = get_next_facet(next_fe);
next_fe = inverse_id(get_prev_edge(next_fe));
}
}
/* other edge at corner at other end of long edge from first corner */
e_id = other_triples[2][0];
fe = get_edge_fe(e_id);
for ( k = 0 ; k < 3 ; k++ )
{ /* traverse fan in all three directions */
fe = get_next_facet(fe);
next_fe = inverse_id(get_prev_edge(fe));
for (;;)
{ if ( !equal_id(get_next_facet(next_fe),get_prev_facet(next_fe)) )
{ /* have found next triple edge */
ee_id = get_fe_edge(next_fe);
if ( equal_element(ee_id,keepe) )
{ /* everything already ok, but adjust facetedges */
}
else if ( equal_id(ee_id,other_triples[2][1]) )
{ /* spread out with new edge */
facetedge_id feb = inverse_id(get_prev_edge(fe));
facetedge_id fea = get_prev_edge(fe);
facet_id fa = get_fe_facet(fe);
facetedge_id newfe = new_facetedge(fa,inverse_id(newe[1]));
facetedge_id newefe = get_edge_fe(inverse_id(newe[1]));
while ( !equal_id(feb,next_fe) )
{ eee_id = get_fe_edge(feb);
remove_vertex_edge(newv[1],eee_id);
set_edge_tailv(eee_id,newv[2]);
feb = get_next_facet(feb);
feb = inverse_id(get_prev_edge(feb));
}
set_next_edge(fea,newfe);
set_prev_edge(newfe,fea);
set_prev_edge(fe,newfe);
set_next_edge(newfe,fe);
set_next_facet(newfe,get_prev_facet(newefe));
set_prev_facet(get_prev_facet(newefe),newfe);
set_next_facet(newefe,newfe);
set_prev_facet(newfe,newefe);
cross_cut(newfe,fe);
}
else if ( equal_id(ee_id,other_triples[1][0]) )
{ /* everything ok */
}
else /* shouldn't get here */
kb_error(2825,"Aborted pop_quad_to_quad halfway through.\n",
WARNING);
break;
}
next_fe = get_next_facet(next_fe);
next_fe = inverse_id(get_prev_edge(next_fe));
}
}
/* final corner */
e_id = other_triples[1][1];
fe = get_edge_fe(e_id);
for ( k = 0 ; k < 3 ; k++ )
{ /* traverse fan in all three directions */
fe = get_next_facet(fe);
next_fe = fe;
for (;;)
{ ee_id = get_fe_edge(next_fe);
if ( !equal_id(get_edge_tailv(ee_id),newv[2]) )
{ remove_vertex_edge(newv[1],ee_id);
set_edge_tailv(ee_id,newv[2]);
}
next_fe = inverse_id(get_prev_edge(next_fe));
if ( !equal_id(get_next_facet(next_fe),get_prev_facet(next_fe)) )
{ /* have found next triple edge */
break;
}
next_fe = get_next_facet(next_fe);
}
}
/* other part of final corner */
e_id = other_triples[2][1];
fe = get_edge_fe(e_id);
for ( k = 0 ; k < 3 ; k++ )
{ /* traverse fan in all three directions */
fe = get_next_facet(fe);
next_fe = fe;
for (;;)
{ ee_id = get_fe_edge(next_fe);
if ( !equal_id(get_edge_tailv(ee_id),newv[2]) )
{ remove_vertex_edge(newv[1],ee_id);
set_edge_tailv(ee_id,newv[2]);
}
next_fe = inverse_id(get_prev_edge(next_fe));
if ( !equal_id(get_next_facet(next_fe),get_prev_facet(next_fe)) )
{ /* have found next triple edge */
break;
}
next_fe = get_next_facet(next_fe);
}
}
/* move vertices apart */
for ( i = 0 ; i < 4 ; i++ )
{ x[i] = get_coord(newv[i]);
for ( j = 0 ; j < 2 ; j++ )
get_edge_side(other_triples[i][j],sides[i][j]);
}
for ( j = 0 ; j < SDIM ; j++ )
{ REAL d;
d = sides[0][0][j]+sides[1][0][j]+sides[2][0][j]+sides[3][0][j];
x[0][j] += d/12;
x[1][j] += d/12;
d = sides[0][1][j]+sides[1][1][j]+sides[2][1][j]+sides[3][1][j];
x[2][j] += d/12;
x[3][j] += d/12;
}
/* Fix up facet edge orders */
for ( i = 0 ; i < 4 ; i++ )
{ facetedge_id next_fe;
int count;
fa = newfe[i];
fb = get_next_facet(fa);
fc = get_prev_facet(fa);
ea = newe[i];
eb = newe[(i+3)%4];
next_fe = inverse_id(get_prev_edge(fb));
for(count=0;count < 10000 ;count++)
{ ec = get_fe_edge(next_fe);
if ( equal_element(ec,ea) )
break; /* ok */
if ( equal_element(ec,eb) )
{ /* have to switch order around edge */
set_prev_facet(fa,fb);
set_prev_facet(fb,fc);
set_prev_facet(fc,fa);
set_next_facet(fa,fc);
set_next_facet(fc,fb);
set_next_facet(fb,fa);
break;
}
next_fe = inverse_id(get_prev_edge(get_prev_facet(next_fe)));
}
if ( count >= 10000 )
{ sprintf(errmsg,"Internal error after pop_quad_to_quad facet %s, bad topology around vertex %s.\n",ELNAME(f_id),ELNAME1(get_edge_tailv(ea)));
kb_error(2831,errmsg,RECOVERABLE);
}
}
/* fix up new facet bodies */
fa = get_fe_facet(newfe[0]);
fe = get_prev_facet(newfe[0]); /* debugging */
fb = get_fe_facet(fe);
b_id = get_facet_body(inverse_id(fb));
set_facet_body(fa,b_id);
set_facet_body(inverse_id(get_fe_facet(newfe[0])),
get_facet_body(get_fe_facet(get_next_facet(newfe[0]))));
set_facet_body(get_fe_facet(newfe[2]),
get_facet_body(inverse_id(get_fe_facet(get_prev_facet(newfe[2])))));
set_facet_body(inverse_id(get_fe_facet(newfe[2])),
get_facet_body(get_fe_facet(get_next_facet(newfe[2]))));
if ( web.modeltype == QUADRATIC )
{ /* fix up edge midpoints */
int bailcount = 0;
for ( i = 0 ; i < 4 ; i++ )
{ edge_id start_e = get_vertex_edge(newv[i]);
edge_id ea;
ea = start_e;
do
{ new_vertex_average(get_edge_midv(ea),VOLKEEP);
ea = get_next_tail_edge(ea);
if ( bailcount++ > 1000 ) break;
} while ( !equal_id(ea,start_e));
}
}
return 1;
} /* end pop_quad_to_quad */
/*****************************************************************************
*
* function: pop_constrained_vertex()
*
* purpose: analyze and pop a vertex on at least one constraint.
*
* return: 1 if popped, 0 if not.
*/
int pop_constrained_vertex(v_id)
vertex_id v_id;
{
conmap_t *vmap = get_v_constraint_map(v_id);
int vhits = v_hit_constraint_count(v_id);
int kind_counts[5][4]; /* indexed by valence, constraints */
edge_id kind_lists[5][4][20]; /* actual edges, for easy reference */
int toohigh=0,triples=0;
unsigned int i,j,val;
edge_id e_id,start_e;
if ( vhits == 3 )
return triple_con_pop(v_id);
for ( i = 0; i < 5 ; i++ )
for ( j = 0 ; j < 4 ; j++ )
kind_counts[i][j] = 0;
/* detect types of edges */
e_id = start_e = get_vertex_edge(v_id);
do
{ int valence = get_edge_valence(e_id);
conmap_t *emap = get_e_constraint_map(e_id);
int hits = 0;
/* see if constraints are at most those of v_id */
for ( i = 1 ; i <= emap[0] ; i++ )
{ int found = 0;
for ( j = 1 ; j <= vmap[0] ; j++ )
if ( emap[i] == (vmap[j] & ~CON_HIT_BIT) )
{ if ( vmap[j] & CON_HIT_BIT )
hits++;
found = 1;
break;
}
if ( !found )
{ if ( verbose_flag )
{ sprintf(msg,"Pop vertex %s fails since constraints of edge %s are not a subset of those of the vertex.\n",ELNAME(v_id),ELNAME1(e_id));
outstring(msg);
}
return 0;
}
}
if ( valence > 3 ) { valence = 4; toohigh++; }
if ( valence == 3 ) triples++;
if ( hits > 3 ) hits = 4;
if ( kind_counts[valence][hits] > 20 )
{ sprintf(errmsg,"Too many edges around vertex %s for pop to handle.\n",
ELNAME(v_id));
kb_error(4001,errmsg,WARNING);
return 0;
}
kind_lists[valence][hits][kind_counts[valence][hits]++] = e_id;
e_id = get_next_tail_edge(e_id);
} while ( !equal_id(e_id,start_e) );
/* see what we have */
if ( toohigh )
{ if ( verbose_flag )
{ sprintf(msg,
"Vertex %s has edges of valence more than 3, so pop edges first.\n",
ELNAME(v_id));
outstring(msg);
}
}
if ( (vhits == 2) && (triples == 1))
return double_con_pop(v_id,kind_lists[3][0][0],kind_lists[1][1]);
val = get_vertex_evalence(v_id);
if ( (vhits == 1) && (kind_counts[1][1]==4) &&
(kind_counts[2][0] == val-4) )
return one_con_pop_4(v_id,kind_lists[1][1],POP_TO_BETTER);
/* test for ok configurations */
if ( (vhits <= 2) && (triples == 0) )
return 0;
if ( triples <= 1 )
return 0;
/* so now have one constraint and at least two triple lines */
if ( (triples == 2) && (kind_counts[3][0] == 2) && (kind_counts[1][1]==4) )
{ /* common case of two unconstrained triple lines with 4 constrained edges */
return one_con_pop_2(v_id,kind_lists[3][0],kind_lists[1][1],POP_TO_BETTER);
}
if ( (triples >= 3) && (kind_counts[3][0] == triples)
&& (kind_counts[1][1]==triples) )
{ /* common case of N unconstrained triple lines with N constrained edges */
return one_con_pop_3(v_id,triples,kind_lists[3][0],kind_lists[1][1],
POP_TO_BETTER);
}
return 0;
}
/*****************************************************************************
*
* function: triple_con_pop()
*
* purpose: Move film out of corner where three constraints meet.
* Does nothing if one adjacent edge is on two constraints.
* Just frees vertex from constraint not used by edges,
* if not a one-sided constraint. Doesn't actually move vertex.
*
* return: 1 if successful, 0 if not
*/
int triple_con_pop(v_id)
vertex_id v_id;
{
conmap_t *vmap = get_v_constraint_map(v_id);
edge_id e_id, start_e;
/* edge_id conedges[2]; */
conmap_t cons[2];
unsigned int ehits=0; /* number of adjacent edges on constraints */
unsigned int i,j;
/* see if any adjacent edge is on two constraints */
/* and find out what constraints are involved */
e_id = start_e = get_vertex_edge(v_id);
do
{ conmap_t *emap = get_e_constraint_map(e_id);
int this_hits = 0;
for ( i = 1 ; i <= emap[0] ; i++ )
{
for ( j = 0 ; j <= vmap[0] ; j++ )
{ if ( (emap[j]==(vmap[j]&~CON_HIT_BIT)) && (vmap[j] & CON_HIT_BIT) )
{ if ( this_hits )
{ /* now second constraint on edge */
return 0;
}
/* conedges[ehits] = e_id; */
cons[ehits] = emap[j];
ehits++;
this_hits++;
}
}
}
e_id = get_next_tail_edge(e_id);
} while ( !equal_id(e_id,start_e) );
/* see if constraint not used by edges is not one-sided */
for ( i = 1 ; i <= vmap[0] ; i++ )
{ if ( !(vmap[i] & CON_HIT_BIT) ) continue;
if ( get_constraint(vmap[i])->attr & (NONPOSITIVE|NONNEGATIVE) ) continue;
for ( j = 0 ; j < ehits ; j++ )
if ( cons[j] == (vmap[i] & ~CON_HIT_BIT) )
continue;
/* now have freeable constraint */
unset_v_constraint_map(v_id,vmap[i]);
return 1;
}
return 0;
}
/*****************************************************************************
*
* function: double_con_pop()
*
* purpose: Pop triple line coming into junction of two constraints.
* Moves triple line end to the constraint it is most
* parallel to. Presumably triple edge got there by deletion
* of a short edge, so probably wants to go on the constraint
* with the single edge.
*
* return: 1 if successful, 0 if not
*/
int double_con_pop(v_id,triple,con_edges)
vertex_id v_id;
edge_id triple; /* the triple edge */
edge_id *con_edges; /* the edges on constraints */
{
conmap_t *vmap = get_v_constraint_map(v_id);
conmap_t cons[2];
conmap_t concounts[2];
unsigned int count;
unsigned int i,j,k;
edge_id cedges[2][2];
REAL tripvec[MAXCOORD];
REAL con_normal[2][MAXCOORD];
REAL dummy;
if ( (get_vattr(v_id) & FIXED) || (get_eattr(con_edges[0]) & FIXED)
|| (get_eattr(con_edges[1]) & FIXED) || (get_eattr(con_edges[2]) & FIXED))
return 0;
concounts[0] = concounts[1] = count = 0;
/* find which constraint used twice */
for ( i = 0 ; i < 3 ; i++ )
{ conmap_t *emap = get_e_constraint_map(con_edges[i]);
for ( j = 1 ; j <= emap[0] ; j++ )
{ /* see if hit by vertex */
for ( k = 1 ; k <= vmap[0] ; k++ )
if ( (emap[j] == (vmap[k] & ~CON_HIT_BIT)) && (vmap[k] & CON_HIT_BIT) )
break;
if ( k > vmap[0] ) continue;
for ( k = 0 ; k < count ; k++ )
{ if ( emap[j] == cons[k] )
{
cedges[k][concounts[k]++] = con_edges[i];
break;
}
}
if ( k == count )
{ cons[k] = emap[j];
concounts[k] = 1;
cedges[k][0] = con_edges[i];
count++;
}
}
}
if ( concounts[0] == 1 )
{ /* swap */
edge_id tempe;
conmap_t temp;
tempe = cedges[0][0];
cedges[0][0] = cedges[1][0];
cedges[0][1] = cedges[1][1];
cedges[1][0] = tempe;
temp = cons[0];
cons[0] = cons[1];
cons[1] = temp;
concounts[0] = 2;
concounts[1] = 1;
}
/* calculate gradients */
for ( i = 0 ; i < 2 ; i++ )
eval_all(get_constraint(cons[i])->formula,get_coord(v_id),SDIM,
&dummy,con_normal[i],v_id);
if (fabs(dot(tripvec,con_normal[0],SDIM)) < fabs(dot(tripvec,con_normal[1],SDIM)))
{ /* v_id goes to single-edge constraint */
/* generated new vertices on junction by refining edges */
edge_refine(cedges[0][0]);
edge_refine(cedges[0][1]);
/* old edge is the one attached to v_id */
set_v_constraint_map(get_edge_headv(cedges[0][0]),cons[1]);
set_v_constraint_map(get_edge_headv(cedges[0][1]),cons[1]);
unset_v_constraint_map(v_id,cons[0]);
unset_e_constraint_map(cedges[0][0],cons[0]);
unset_e_constraint_map(cedges[0][1],cons[0]);
set_e_constraint_map(cedges[0][0],cons[1]);
set_e_constraint_map(cedges[0][1],cons[1]);
}
else
{ /* move to double-edge constraint */
edge_refine(cedges[1][0]);
/* old edge is the one attached to v_id */
set_v_constraint_map(get_edge_headv(cedges[1][0]),cons[0]);
unset_v_constraint_map(v_id,cons[1]);
unset_e_constraint_map(cedges[1][0],cons[1]);
set_e_constraint_map(cedges[1][0],cons[0]);
}
return 1;
}
/***************************************************************************
*
* function: one_con_pop_2()
*
* purpose: pop a specific configuration of two triple edges on vertex
* with one constraint. Favors simple pull apart of triple edges.
*
* return: 1 if successful
*/
int one_con_pop_2(v_id,triples,con_edges,mode)
vertex_id v_id;
edge_id *triples;
edge_id *con_edges;
int mode; /* POP_TO_OPEN or POP_TO_TWIST or POP_BETTER */
{ vertex_id newv;
edge_id newe,e_id;
facetedge_id fe,start_fe,newfe;
unsigned int i,j,k;
REAL sides[2][2][MAXCOORD];
REAL mag[2][2];
REAL *x;
edge_id attached[2][2]; /* which constraint edges attached to which trip */
int atcount[2];
conmap_t con=0,*vmap; /* which constraint involved */
int n;
REAL pull[2][MAXCOORD]; /* separating forces for the two ways */
if ( get_vattr(v_id) & FIXED ) return 0;
/* see which constraint edges attached to which triple, and get in order */
atcount[0] = atcount[1] = 0;
for ( k = 0 ; k < 2 ; k++ ) /* for each triple edge */
{ int triple_second_flag = 0;
start_fe = get_edge_fe(triples[k]);
for ( i = 0 ; i < 3 ; i++ )
{
fe = inverse_id(get_prev_edge(start_fe));
for(;;)
{
if ( equal_id(triples[1-k],get_fe_edge(fe)) )
{ if ( i == 1 )
triple_second_flag = 1;
break;
}
e_id = get_fe_edge(fe);
if ( equal_id(fe,get_next_facet(fe)) )
{ /* found valence 1 edge */
attached[k][atcount[k]++] = e_id;
break;
}
fe = inverse_id(get_prev_edge(get_next_facet(fe)));
}
start_fe = get_next_facet(start_fe);
}
if ( triple_second_flag )
{ /* swap into standard order */
edge_id temp = attached[k][0];
attached[k][0] = attached[k][1];
attached[k][1] = temp;
}
for ( i = 0 ; i < 2 ; i++ )
get_edge_side(attached[k][i],sides[k][i]);
}
/* see which constraint involved */
vmap = get_v_constraint_map(v_id);
for ( i = 1; i <= vmap[0] ; i++ )
if ( vmap[i] & CON_HIT_BIT )
{ con = vmap[i] & ~CON_HIT_BIT;
break;
}
/* figure out which way it should pop according to edges on constraints */
if ( mode == POP_TO_BETTER )
{ for ( i = 0 ; i < 2 ; i++ )
for ( j = 0 ; j < 2 ; j++ )
mag[i][j] = dot(sides[i][j],sides[i][j],SDIM);
for ( n = 0 ; n < SDIM ; n++ )
{ pull[0][n] = sides[0][0][n]/mag[0][0]+sides[1][1][n]/mag[1][1]
-sides[0][1][n]/mag[0][1]-sides[1][0][n]/mag[1][0];
pull[1][n] = sides[0][0][n]/mag[0][0]+sides[0][1][n]/mag[0][1]
-sides[1][0][n]/mag[1][0]-sides[1][1][n]/mag[1][1];
}
if ( dot(pull[0],pull[0],SDIM) < 1.2*dot(pull[1],pull[1],SDIM) )
mode = POP_TO_OPEN;
else
mode = POP_TO_TWIST;
}
if ( mode == POP_TO_OPEN )
{ /* simple pull two triple edges apart */
newv = dup_vertex(v_id);
newe = new_edge(v_id,newv,NULLID);
set_e_conmap(newe,get_v_constraint_map(v_id));
/* move stuff around second triple edge to newv */
remove_vertex_edge(v_id,triples[1]);
set_edge_tailv(triples[1],newv);
start_fe = get_edge_fe(triples[1]);
for ( i = 0 ; i < 3 ; i++ )
{
fe = inverse_id(get_prev_edge(start_fe));
for(;;)
{
if ( equal_id(triples[0],get_fe_edge(fe)) )
{ /* take care of splitting facet(s) between triples */
facet_id f_id = inverse_id(get_fe_facet(fe));
newfe = new_facetedge(f_id,newe);
set_edge_fe(newe,newfe);
set_next_facet(newfe,newfe);
set_prev_facet(newfe,newfe);
set_prev_edge(newfe,inverse_id(fe));
set_next_edge(newfe,inverse_id(get_prev_edge(fe)));
set_prev_edge(inverse_id(get_prev_edge(fe)),newfe);
set_next_edge(inverse_id(fe),newfe);
cross_cut(inverse_id(fe),newfe);
break;
}
e_id = get_fe_edge(fe);
remove_vertex_edge(v_id,e_id);
set_edge_tailv(e_id,newv);
if ( equal_id(fe,get_next_facet(fe)) )
{ /* found valence 1 edge */
break;
}
fe = inverse_id(get_prev_edge(get_next_facet(fe)));
}
start_fe = get_next_facet(start_fe);
}
/* move vertices apart a bit */
x = get_coord(newv);
for ( n = 0 ; n < SDIM ; n++ )
x[n] += sides[0][0][n]/6 + sides[0][1][n]/6 + sides[1][0][n]/3
+ sides[1][1][n]/3;
x = get_coord(v_id);
for ( n = 0 ; n < SDIM ; n++ )
x[n] += sides[0][0][n]/3 + sides[0][1][n]/3 + sides[1][0][n]/6
+ sides[1][1][n]/6;
}
else
{ /* create twist facet in pull-apart */
vertex_id newv1,newv2;
edge_id newe1,newe2,newe3;
facet_id newf;
facetedge_id fe,prevfe,newfe1,newfe2,newfe3,newfe4,newfe5;
REAL tsides[2][MAXCOORD];
/* v_id will be released from constraint and moved off constraint */
newv1 = dup_vertex(v_id);
newv2 = dup_vertex(v_id);
newe1 = new_edge(v_id,newv1,triples[0]);
newe2 = new_edge(v_id,newv2,triples[0]);
newe3 = new_edge(newv1,newv2,NULLID);
set_e_conmap(newe3,get_v_constraint_map(v_id));
unset_v_constraint_map(v_id,con);
/* create twist facet */
newf = new_facet();
newfe1 = new_facetedge(newf,newe1);
newfe2 = new_facetedge(inverse_id(newf),newe2);
newfe3 = new_facetedge(newf,newe3);
set_edge_fe(newe1,newfe1);
set_edge_fe(newe2,newfe2);
set_edge_fe(newe3,newfe3);
set_facet_fe(newf,newfe1);
set_next_edge(newfe1,newfe3);
set_next_edge(newfe2,inverse_id(newfe3));
set_next_edge(newfe3,inverse_id(newfe2));
set_prev_edge(newfe1,inverse_id(newfe2));
set_prev_edge(newfe2,inverse_id(newfe1));
set_prev_edge(newfe3,newfe1);
set_next_facet(newfe3,newfe3);
set_prev_facet(newfe3,newfe3);
/* reconnect wings */
remove_vertex_edge(v_id,attached[0][0]);
remove_vertex_edge(v_id,attached[0][1]);
remove_vertex_edge(v_id,attached[1][0]);
remove_vertex_edge(v_id,attached[1][1]);
set_edge_tailv(attached[0][0],newv2);
set_edge_tailv(attached[0][1],newv1);
set_edge_tailv(attached[1][0],newv1);
set_edge_tailv(attached[1][1],newv2);
fe = get_edge_fe(attached[0][0]);
prevfe = get_prev_edge(fe);
newfe4 = new_facetedge(get_fe_facet(fe),newe2);
set_next_edge(prevfe,newfe4);
set_prev_edge(newfe4,prevfe);
set_next_edge(newfe4,fe);
set_prev_edge(fe,newfe4);
set_next_facet(newfe2,newfe4);
set_prev_facet(newfe4,newfe2);
cross_cut(newfe4,fe);
fe = get_edge_fe(attached[1][1]);
prevfe = get_prev_edge(fe);
newfe5 = new_facetedge(get_fe_facet(fe),newe2);
set_next_edge(prevfe,newfe5);
set_prev_edge(newfe5,prevfe);
set_next_edge(newfe5,fe);
set_prev_edge(fe,newfe5);
set_next_facet(newfe5,newfe2);
set_prev_facet(newfe2,newfe5);
set_next_facet(newfe4,newfe5);
set_prev_facet(newfe5,newfe4);
cross_cut(newfe5,fe);
fe = get_edge_fe(attached[1][0]);
prevfe = get_prev_edge(fe);
newfe4 = new_facetedge(get_fe_facet(fe),newe1);
set_next_edge(prevfe,newfe4);
set_prev_edge(newfe4,prevfe);
set_next_edge(newfe4,fe);
set_prev_edge(fe,newfe4);
set_next_facet(newfe1,newfe4);
set_prev_facet(newfe4,newfe1);
cross_cut(newfe4,fe);
fe = get_edge_fe(attached[0][1]);
prevfe = get_prev_edge(fe);
newfe5 = new_facetedge(get_fe_facet(fe),newe1);
set_next_edge(prevfe,newfe5);
set_prev_edge(newfe5,prevfe);
set_next_edge(newfe5,fe);
set_prev_edge(fe,newfe5);
set_next_facet(newfe5,newfe1);
set_prev_facet(newfe1,newfe5);
set_next_facet(newfe4,newfe5);
set_prev_facet(newfe5,newfe4);
cross_cut(newfe5,fe);
set_facet_body(newf,get_facet_body(inverse_id(get_fe_facet(newfe5))));
set_facet_body(inverse_id(newf),get_facet_body(get_fe_facet(newfe4)));
/* move vertices */
x = get_coord(newv1);
for ( n = 0 ; n < SDIM ; n++ )
x[n] += sides[1][0][n]/3 + sides[0][1][n]/3 + sides[0][0][n]/6
+ sides[1][1][n]/6;
x = get_coord(newv2);
for ( n = 0 ; n < SDIM ; n++ )
x[n] += sides[1][0][n]/6 + sides[0][1][n]/6 + sides[0][0][n]/3
+ sides[1][1][n]/3;
x = get_coord(v_id);
get_edge_side(triples[0],tsides[0]);
get_edge_side(triples[1],tsides[1]);
for ( n = 0 ; n < SDIM ; n++ )
x[n] += 0.15*tsides[0][n] + 0.15*tsides[1][n];
}
return 1;
}
/***************************************************************************
*
* function: one_con_pop_3()
*
* purpose: pop a specific configuration of N triple edges on vertex
* with one constraint. Each triple edge is on a fin with
* one constrained edge.
*
* return: 1 if successful
*/
#define MAXTRIPS 20
int one_con_pop_3(v_id,tripcount,triples,con_edges,mode)
vertex_id v_id;
int tripcount;
edge_id *triples;
edge_id *con_edges;
int mode; /* POP_TO_OPEN or POP_TO_TRIPLE or POP_BETTER */
{
edge_id e_id;
unsigned int i;
REAL sides[MAXTRIPS][MAXCOORD];
REAL tsides[MAXTRIPS][MAXCOORD];
REAL mag[MAXTRIPS];
REAL net[MAXCOORD];
REAL *x;
conmap_t con=0,*vmap; /* which constraint involved */
int j,n,m;
facetedge_id fe;
if ( get_vattr(v_id) & FIXED ) return 0;
/* see which constraint involved */
vmap = get_v_constraint_map(v_id);
for ( i = 1; i <= vmap[0] ; i++ )
if ( vmap[i] & CON_HIT_BIT )
{ con = vmap[i] & ~CON_HIT_BIT;
break;
}
/* get triple edges and constrained edges lined up */
fe = get_edge_fe(con_edges[0]);
fe = inverse_id(get_prev_edge(fe));
while ( equal_id(get_next_facet(fe),get_prev_facet(fe)) )
fe = inverse_id(get_prev_edge(get_next_facet(fe)));
fe = get_prev_facet(fe);
for ( m = 0 ; m < tripcount ; m++ )
{ facetedge_id ffe;
triples[m] = get_fe_edge(fe);
/* seek down to corresponding constrained edge */
ffe = get_next_facet(fe);
ffe = inverse_id(get_prev_edge(ffe));
while ( !equal_id(get_next_facet(ffe),ffe) )
ffe = inverse_id(get_prev_edge(get_next_facet(ffe)));
con_edges[m] = get_fe_edge(ffe);
/* now over to next triple */
fe = get_prev_facet(fe);
fe = inverse_id(get_prev_edge(fe));
while ( equal_id(get_next_facet(fe),get_prev_facet(fe)) )
fe = inverse_id(get_prev_edge(get_next_facet(fe)));
}
for ( m = 0 ; m < tripcount ; m++ )
get_edge_side(triples[m],tsides[m]);
for ( m = 0 ; m < tripcount ; m++ )
{ get_edge_side(con_edges[m],sides[m]);
mag[m] = sqrt(dot(tsides[m],tsides[m],SDIM));
}
/* figure out which way it should pop according to edges on constraints */
if ( mode == POP_TO_BETTER )
{ for ( n = 0 ; n < SDIM ; n++ )
for ( m = 0, net[n] = 0.0 ; m < tripcount ; m++ )
net[n] += tsides[m][n]/mag[m];
if ( sqrt(dot(net,net,SDIM)) < 0.7*tripcount )
mode = POP_TO_OPEN;
else
mode = POP_TO_TRIPLE;
}
/* do the pop */
if ( mode == POP_TO_OPEN )
{ /* make open triangle */
vertex_id newv[MAXTRIPS];
edge_id newe[MAXTRIPS];
facetedge_id next_fe,fe,start_fe,newfe;
newv[0] = v_id;
for ( m = 1 ; m < tripcount ; m++ )
newv[m] = dup_vertex(v_id);
for ( m = 0 ; m < tripcount ; m++ )
{ newe[m] = new_edge(newv[m],newv[(m+1)%tripcount],NULLID);
set_e_conmap(newe[m],get_v_constraint_map(v_id));
}
/* move stuff around last two constraint edges to new vertices */
/* and putting in new edges */
for ( m = 0 ; m < tripcount ; m++ )
{ int found_triple;
if ( m > 0 )
{ remove_vertex_edge(v_id,con_edges[m]);
set_edge_tailv(con_edges[m],newv[m]);
}
start_fe = get_edge_fe(con_edges[m]);
fe = inverse_id(get_prev_edge(start_fe));
for( found_triple = 0 ; !found_triple ; fe = next_fe )
{
next_fe = inverse_id(get_prev_edge(get_next_facet(fe)));
if ( !equal_id(get_next_facet(fe),get_prev_facet(fe)) )
{ /* take care of splitting facet(s) between triples */
facet_id f_id;
facetedge_id ffe,prevfe;
ffe = get_next_facet(fe);
f_id = inverse_id(get_fe_facet(ffe));
newfe = new_facetedge(f_id,newe[m]);
set_edge_fe(newe[m],newfe);
set_next_facet(newfe,newfe);
set_prev_facet(newfe,newfe);
prevfe = inverse_id(get_prev_edge(ffe));
set_prev_edge(newfe,inverse_id(ffe));
set_next_edge(newfe,prevfe);
set_prev_edge(prevfe,newfe);
set_next_edge(inverse_id(ffe),newfe);
/* continue on, resetting endpoints on crossing face */
if ( m != tripcount-1 )
while (equal_id(get_next_facet(prevfe),get_prev_facet(prevfe)))
{ e_id = get_fe_edge(prevfe);
remove_vertex_edge(v_id,e_id);
set_edge_tailv(e_id,newv[m+1]);
prevfe = inverse_id(get_prev_edge(get_next_facet(prevfe)));
}
cross_cut(newfe,get_next_edge(newfe));
found_triple = 1;
}
e_id = get_fe_edge(fe);
if ( m > 0 )
{ remove_vertex_edge(v_id,e_id);
set_edge_tailv(e_id,newv[m]);
}
}
}
/* move vertices apart a bit */
for ( m = 0 ; m < tripcount ; m++ )
{ x = get_coord(newv[m]);
for ( n = 0 ; n < SDIM ; n++ )
{ x[n] += 0.5*sides[m][n];
for ( j = 0 ; j < tripcount ; j++ )
x[n] += 0.5*sides[j][n]/tripcount;
}
}
}
else
{ /* create pulled-out triple edge */
vertex_id newv;
edge_id newe;
facetedge_id fe,prevfe,newfe[MAXTRIPS];
/* v_id will be released from constraint and moved off constraint */
newv = dup_vertex(v_id);
newe = new_edge(v_id,newv,triples[0]);
unset_v_constraint_map(v_id,con);
/* reconnect wings */
for ( m = 0 ; m < tripcount ; m++ )
{ remove_vertex_edge(v_id,con_edges[m]);
set_edge_tailv(con_edges[m],newv);
fe = get_edge_fe(con_edges[m]);
prevfe = get_prev_edge(fe);
newfe[m] = new_facetedge(get_fe_facet(fe),newe);
set_next_edge(prevfe,newfe[m]);
set_prev_edge(newfe[m],prevfe);
set_next_edge(newfe[m],fe);
set_prev_edge(fe,newfe[m]);
cross_cut(newfe[m],fe);
}
set_edge_fe(newe,newfe[0]);
for ( m = 0 ; m < tripcount ; m++ )
{ set_next_facet(newfe[m],newfe[(m+1)%tripcount]);
set_prev_facet(newfe[(m+1)%tripcount],newfe[m]);
}
fe_reorder(newe); /* make sure in proper geometric order */
/* move vertex */
x = get_coord(v_id);
for ( n = 0 ; n < SDIM ; n++ )
{ for ( m= 0 ; m < tripcount ; m++ )
x[n] += 0.3*tsides[m][n]/tripcount;
}
}
return 1;
}
/***************************************************************************
*
* function: one_con_pop_4()
*
* purpose: pop a specific configuration of two films meeting at a
* point on a constraint, i.e. parting mounds.
* Or joining mounds that are touching at one vertex.
*
* return: 1 if successful
*/
int one_con_pop_4(v_id,con_edges,mode)
vertex_id v_id;
edge_id *con_edges;
int mode; /* POP_TO_OPEN or POP_TO_TRIANGLE or POP_TO_BETTER */
{
vertex_id newv[2];
int i;
REAL sides[4][MAXCOORD];
REAL mag[4];
facetedge_id fe,next_fe;
if ( get_vattr(v_id) & FIXED ) return 0;
/* see which constraint edges belong together */
fe = get_edge_fe(con_edges[0]);
do
{ fe = inverse_id(get_prev_edge(fe));
next_fe = get_next_facet(fe);
if ( equal_id(fe,next_fe) )
{ /* found it */
edge_id other_e = get_fe_edge(fe);
for ( i = 2 ; i < 4 ; i++ ) /* get in second spot */
if ( equal_id(other_e,con_edges[i]) )
{ con_edges[i] = con_edges[1];
con_edges[1] = other_e;
}
break;
}
fe = next_fe;
} while (1);
/* get side vectors */
for ( i = 0 ; i < 4 ; i++ )
{ get_edge_side(con_edges[i],sides[i]);
mag[i] = sqrt(dot(sides[i],sides[i],SDIM));
}
/* figure out which way it should pop according to edges on constraints */
if ( mode == POP_TO_BETTER )
{ if ( pop_disjoin_flag )
mode = POP_TO_OPEN;
/* if included angles bigger than exterior, then merge */
else if ( acos(dot(sides[0],sides[1],SDIM)/mag[0]/mag[1])
+ acos(dot(sides[2],sides[3],SDIM)/mag[2]/mag[3]) > M_PI )
mode = POP_TO_TRIANGLE;
else
mode = POP_TO_OPEN;
}
/* do the pop */
if ( mode == POP_TO_OPEN )
{ /* make separate vertices */
edge_id other_e;
newv[0] = v_id;
newv[1] = dup_vertex(v_id);
/* reconnect edges */
next_fe = get_edge_fe(con_edges[2]);
do
{
fe = next_fe;
other_e = get_fe_edge(fe);
remove_vertex_edge(v_id,other_e);
set_edge_tailv(other_e,newv[1]);
fe = inverse_id(get_prev_edge(fe));
next_fe = get_next_facet(fe);
} while ( !equal_id(other_e,con_edges[3]) );
set_vertex_edge(newv[0],con_edges[0]);
set_vertex_edge(newv[1],con_edges[2]);
/* no reason to move vertices apart a bit */
}
else
{ /* create pulled-out triangle */
facetedge_id fe1,fe2,newfe1,newfe2,prev1,prev2;
REAL *xold,*xnew;
edge_id newe;
facet_id f1,f2;
facetedge_id fe_a,fe_b,cc_fe;
body_id b1f,b1b,b2f,b2b;
/* get con_edges in canonical order */
if ( dot(sides[0],sides[3],SDIM)*mag[1]*mag[2]
+ dot(sides[1],sides[2],SDIM)*mag[0]*mag[3]
< dot(sides[0],sides[2],SDIM)*mag[1]*mag[3]
+ dot(sides[1],sides[3],SDIM)*mag[0]*mag[2])
{ edge_id tmpe = con_edges[2]; con_edges[2] = con_edges[3];
con_edges[3] = tmpe;
for ( i = 0 ; i < SDIM ; i++ )
{ REAL t = sides[2][i]; sides[2][i] = sides[3][i]; sides[3][i] = t; }
}
/* first, split vertex and put edge between */
newv[0] = v_id;
newv[1] = dup_vertex(v_id);
newe = new_edge(newv[0],newv[1],NULLID);
f1 = get_fe_facet(get_edge_fe(con_edges[1]));
f2 = get_fe_facet(get_edge_fe(con_edges[2]));
newfe1 = new_facetedge(f1,newe);
newfe2 = new_facetedge(f2,newe);
set_edge_fe(newe,newfe1);
set_next_facet(newfe1,newfe2);
set_prev_facet(newfe1,newfe2);
set_next_facet(newfe2,newfe1);
set_prev_facet(newfe2,newfe1);
/* reconnect edges */
remove_vertex_edge(v_id,con_edges[1]);
set_edge_tailv(con_edges[1],newv[1]);
remove_vertex_edge(v_id,con_edges[2]);
set_edge_tailv(con_edges[2],newv[1]);
fe1 = get_edge_fe(con_edges[1]);
prev1 = get_prev_edge(fe1);
set_prev_edge(newfe1,prev1);
set_next_edge(prev1,newfe1);
set_next_edge(newfe1,fe1);
set_prev_edge(fe1,newfe1);
fe2 = get_edge_fe(con_edges[2]);
prev2 = get_prev_edge(fe2);
set_prev_edge(newfe2,prev2);
set_next_edge(prev2,newfe2);
set_next_edge(newfe2,fe2);
set_prev_edge(fe2,newfe2);
cross_cut(prev1,newfe1);
cross_cut(prev2,newfe2);
/* move vertices apart a bit */
xold = get_coord(v_id);
xnew = get_coord(newv[1]);
for ( i = 0 ; i < SDIM ; i++ )
{ xold[i] += 0.1 * sides[0][i] + 0.1 * sides[3][i];
xnew[i] += 0.1 * sides[1][i] + 0.1 * sides[2][i];
}
/* refine the new edge */
cc_fe = get_next_edge(newfe1); /* need to save for later */
edge_refine(newe);
/* Septum if bodies disagree */
b1f = get_facet_body(f1);
b1b = get_facet_body(inverse_id(f1));
b2f = get_facet_body(f2);
b2b = get_facet_body(inverse_id(f2));
/* figure out which side needs the septum, if any */
fe_a = fe_b = NULLID;
if ( !equal_id(b1b,b2f) )
{ fe_a = newfe1;
fe_b = get_prev_edge(cc_fe);
}
else if ( !equal_id(b1f,b2b) )
{ fe_a = inverse_id(get_prev_edge(cc_fe));
fe_b = inverse_id(newfe1);
}
if ( valid_id(fe_a) )
{ /* put in new facet */
edge_id span_e = new_edge( get_fe_headv(fe_b),get_fe_tailv(fe_a),v_id);
facet_id span_f = new_facet();
facetedge_id span_fe = new_facetedge(span_f,span_e);
facetedge_id fe_a_new = new_facetedge(span_f,get_fe_edge(fe_a));
facetedge_id fe_b_new = new_facetedge(span_f,get_fe_edge(fe_b));
facetedge_id fe_c,fe_d;
set_facet_fe(span_f,span_fe);
set_edge_fe(span_e,span_fe);
set_facet_density(span_f,1.0);
set_next_edge(span_fe,fe_a_new);
set_next_edge(fe_a_new,fe_b_new);
set_next_edge(fe_b_new,span_fe);
set_prev_edge(span_fe,fe_b_new);
set_prev_edge(fe_b_new,fe_a_new);
set_prev_edge(fe_a_new,span_fe);
set_next_facet(span_fe,span_fe);
set_prev_facet(span_fe,span_fe);
fe_c = get_next_facet(fe_a);
fe_d = get_next_facet(fe_b);
set_next_facet(fe_a,fe_a_new);
set_next_facet(fe_a_new,fe_c);
set_prev_facet(fe_c,fe_a_new);
set_prev_facet(fe_a_new,fe_a);
set_next_facet(fe_b,fe_b_new);
set_next_facet(fe_b_new,fe_d);
set_prev_facet(fe_d,fe_b_new);
set_prev_facet(fe_b_new,fe_b);
set_facet_body(span_f,get_facet_body(inverse_id(get_fe_facet(fe_a))));
set_facet_body(inverse_id(span_f),get_facet_body(get_fe_facet(fe_c)));
}
} /* end pulled-out triangle */
return 1;
}
/**************************************************************************
*
* function: pop_tri_to_edge_con()
*
* purpose: Implement pop_tri_to_edge for triple edge with tail on constraint.
* Algorithm: deletes edge, calls one_con_pop_3 in proper mode.
* Called from pop_tri_to_edge(), which has checked valence and
* number of triple edges at head.
*
* return: 1 if successful, 0 if not.
*/
int pop_edge_to_tri_con(e_id)
edge_id e_id;
{ vertex_id v_id = get_edge_tailv(e_id);
edge_id ee_id, start_e;
int retval;
int concount = 0,tripcount = 0;
edge_id triples[20];
edge_id con_edges[20];
retval = eliminate_edge(e_id);
if ( retval == 0 )
return 0;
free_element(e_id); /* quirk of eliminate_edge */
/* gather data for one_con_pop_3 */
ee_id = start_e = get_vertex_edge(v_id);
do
{ int valence = get_edge_valence(ee_id);
if ( valence == 3 )
triples[tripcount++] = ee_id;
if ( valence == 1 )
con_edges[concount++] = ee_id;
ee_id = get_next_tail_edge(ee_id);
if ( tripcount >= 20 || concount >= 20 )
{ if ( verbose_flag )
{ sprintf(msg,"Can't handle over 20-valence edge %s! Sorry.\n",
ELNAME(e_id));
outstring(msg);
}
return 0;
}
} while ( !equal_id(ee_id,start_e) );
if ( tripcount != concount )
{ if ( verbose_flag )
{ sprintf(msg,"Pop_edge_to_tri not applicable to edge %s.\n",ELNAME(e_id));
outstring(msg);
}
return 0;
}
return one_con_pop_3(v_id,tripcount,triples,con_edges,POP_TO_OPEN);
}
evolver-2.30c.dfsg/src/web.h 0000644 0001753 0001753 00000022311 11410765113 016142 0 ustar hazelsct hazelsct /*************************************************************
* This file is part of the Surface Evolver source code. *
* Programmer: Ken Brakke, brakke@susqu.edu *
*************************************************************/
/**********************************************************************
*
* The ultimate structure for a whole surface , including all global
* variables needed to export for distributed computing.
*/
#ifdef __cplusplus
extern "C" {
#endif
/* structure type name different from structure variable name since
Visual C is incompetent at distinguishing in debugger. */
struct webstruct {
struct skeleton skel[NUMELEMENTS];
int sizes[NUMELEMENTS]; /* allocated space for element structure */
int usedsizes[NUMELEMENTS]; /* used space for element structure */
struct element **elhashtable; /* id hash list of element pointers */
int elhashcount; /* actual number of live entries */
int elhashmask; /* for picking off index bits of id hash */
int elhashsize; /* size of hash table; power of 2 */
int sdim; /* dimension of ambient space */
int dimension; /* where tension resides */
int representation; /* STRING, SOAPFILM, or SIMPLEX */
int modeltype; /* QUADRATIC, LINEAR, or LAGRANGE; see defines below */
int lagrange_order; /* polynomial order of elements */
int headvnum; /* number of head vertex in edge list */
int maxparam; /* maximum number of parameters in any boundary */
int maxcon; /* number of constraint structures allocated */
int highcon; /* highest constraint number used */
struct constraint *constraints; /* constraint definitions */
conmap_t con_global_map[MAXCONPER]; /* global vertex constraints */
int con_global_count; /* number of global vertex constraints */
REAL tolerance; /* constraint error tolerance */
REAL target_tolerance; /* error tolerance for extensive constraints */
int bdrymax; /* number of boundary structures allocated */
int highbdry; /* highest boundary number used */
struct boundary *boundaries; /* for free boundaries */
int diffusion_flag; /* whether diffusion in effect */
REAL diffusion_const; /* coefficient for diffusion */
REAL simplex_factorial; /* content correction factor for determinant */
int torus_clip_flag;
int torus_body_flag;
int symmetric_content; /* 1 if volumes use symmetric divergence */
int h_inverse_metric_flag; /* for laplacian of curvature */
REAL meritfactor; /* for multiplying figure of merit */
int gravflag; /* whether gravity is on */
REAL grav_const; /* multiplier for gravitational force */
int convex_flag; /* whether any convex boundaries present */
int pressflag; /* whether prescribed pressures present */
int constr_flag; /* set if there are any one-sided constraints */
int hide_flag; /* set for hidden surface removal */
int motion_flag; /* set for fixed scale of motion;
otherwise seek minimum. */
int symmetry_flag; /* whether symmetry group in effect */
int torus_flag; /* whether working in toroidal domain */
int full_flag; /* whether torus solidly packed with bodies */
int pressure_flag; /* whether pressure used dynamically */
int projection_flag; /* whether to project */
int area_norm_flag; /* whether to normalize force by area surrounding vertex */
int norm_check_flag; /* whether area normalization checks normal deviation */
REAL norm_check_max; /* maximum allowable deviation */
int vol_flag; /* whether body volumes up to date */
int jiggle_flag; /* whether to jiggle vertices at each move */
int homothety; /* flag for homothety adjustment each iteration */
int wulff_flag; /* whether we are using wulff shapes for energy */
int wulff_count; /* number of Wulff vectors read in */
char wulff_name[60]; /* Wulff file or keyword */
vertex_id zoom_v; /* vertex to zoom on */
REAL zoom_radius; /* current zoom radius */
REAL total_area;
REAL total_area_addends[MAXADDENDS]; /* for binary tree addition */
REAL total_energy;
REAL total_energy_addends[MAXADDENDS]; /* for binary tree addition */
REAL spring_energy;
int total_facets;
int bodycount; /* number of bodies */
body_id outside_body; /* a body surrounding all others */
REAL scale; /* force to motion scale factor */
REAL scale_scale; /* over-relaxation factor */
REAL maxscale; /* upper limit on scale factor */
REAL pressure; /* ambient pressure */
REAL min_area; /* criterion on weeding out small triangles */
REAL min_length; /* criterion on weeding out small triangles */
REAL max_len; /* criterion for dividing long edges */
REAL max_angle; /* max allowed deviation from parallelism */
REAL temperature; /* "temperature" for jiggling */
REAL spring_constant; /* for forcing edges to conform to boundary */
int gauss1D_order; /* order for gaussian 1D integration */
int gauss2D_order; /* order for gaussian 2D integration */
REAL torusv; /* unit cell volume or area */
REAL **torus_period;
REAL **inverse_periods;/* inverse matrix of torus periods */
REAL **torus_display_period;
REAL display_origin[MAXCOORD];
REAL **inverse_display_periods;/* inverse of torus display periods */
int metric_flag; /* set if background metric in force */
int conformal_flag; /* set for conformal metrics */
struct expnode metric[MAXCOORD][MAXCOORD]; /* metric component functions */
/* Some counters. New scheme: Using word of flag bits for having-been-
reported status and needing-reported status, so exec() doesn't have
to zero these for each call to exec. */
/* Counts that are the result of mass action only are reported
immediately */
int equi_count;
int edge_delete_count;
int facet_delete_count;
int edge_refine_count;
int facet_refine_count;
int vertex_dissolve_count;
int edge_dissolve_count;
int facet_dissolve_count;
int body_dissolve_count;
int edge_reverse_count;
int facet_reverse_count;
int vertex_pop_count;
int edge_pop_count;
int pop_tri_to_edge_count;
int pop_edge_to_tri_count;
int pop_quad_to_quad_count;
int where_count;
int edgeswap_count;
int t1_edgeswap_count;
int fix_count;
int unfix_count;
int notch_count;
/* flag words and bits */
int counts_reported;
int counts_changed;
#define equi_count_bit 0x00000001
#define weed_count_bit 0x00000002
#define edge_delete_count_bit 0x00000004
#define facet_delete_count_bit 0x00000008
#define edge_refine_count_bit 0x00000010
#define facet_refine_count_bit 0x00000020
#define notch_count_bit 0x00000040
#define vertex_dissolve_count_bit 0x00000080
#define edge_dissolve_count_bit 0x00000100
#define facet_dissolve_count_bit 0x00000200
#define body_dissolve_count_bit 0x00000400
#define vertex_pop_count_bit 0x00000800
#define edge_pop_count_bit 0x00001000
#define pop_tri_to_edge_count_bit 0x00004000
#define pop_edge_to_tri_count_bit 0x00008000
#define pop_quad_to_quad_count_bit 0x00010000
#define where_count_bit 0x00020000
#define edgeswap_count_bit 0x00040000
#define fix_count_bit 0x00080000
#define unfix_count_bit 0x00100000
#define t1_edgeswap_count_bit 0x00200000
#define edge_reverse_count_bit 0x00400000
#define facet_reverse_count_bit 0x00800000
/* here follows stuff moved from independent globals to inside web
so as to be easily exported. Previous global names are defined
to web fields elsewhere.
*/
DY_OFFSET dy_gen_quants_w;
int gen_quant_count_w;
int gen_quant_alloc_w;
int global_count;
int maxglobals; /* number allocated */
int perm_global_count;
int max_perm_globals; /* number allocated */
DY_OFFSET dy_meth_inst_w; /* for storing instance structures */
int meth_inst_alloc_w; /* number allocated */
int meth_inst_count_w; /* number defined */
/* global method instances, applying to every element of type */
int global_meth_inst_w[NUMELEMENTS][MAXGLOBINST]; /* lists */
int global_meth_inst_count_w[NUMELEMENTS];
/* flags telling which quantity calculations necessary */
/* flag set for Q_ENERGY,Q_FIXED, or Q_INFO if any element
needs a quantity calculated */
int quant_flags_w[NUMELEMENTS];
DY_OFFSET dy_freestart_w; /* initial block of freelist, 0 if none */
#define dy_freestart web.dy_freestart_w
DY_OFFSET dy_globals_w; /* global variable table */
struct global *dy_perm_globals_w;
DY_OFFSET dy_globalshash_w; /* hash list for global variables */
/* common */
int meth_attr[NUMELEMENTS] ; /* method instances list */
int mpi_export_attr[NUMELEMENTS] ; /* method instances list */
};
extern struct webstruct web;
#ifdef __cplusplus
}
#endif
evolver-2.30c.dfsg/src/softimag.c 0000644 0001753 0001753 00000004721 11410765113 017176 0 ustar hazelsct hazelsct /*************************************************************
* This file is part of the Surface Evolver source code. *
* Programmer: Ken Brakke, brakke@susqu.edu *
*************************************************************/
/*****************************************************************
*
* File: softimag.c
*
* Purpose: Triangle list file output for Softimage input.
*/
#include "include.h"
static FILE *fd;
/*****************************************************************
*
* Function: softimage()
*
* Purpose: Write Softimage format files.
*/
void softimage()
{
char file_name[100];
char name[100];
vertex_id v_id;
facet_id f_id;
int *vnumber;
int n;
prompt("Enter file name (no suffix): ",name,sizeof(name));
/* model file */
strcpy(file_name,name);
strcat(file_name,".mdl");
fd = fopen(file_name,"w");
if ( fd == NULL )
{ perror(file_name);
return;
}
fprintf(fd,"SOFTIMAGE 4D Creative Environment v 1.6 \"ASCII\"\n\n\n");
fprintf(fd," MODL \"%s\"\n {\n type PMSH\n",name);
fprintf(fd," nbdef 1\n");
fprintf(fd," scal 1.000000 1.000000 1.000000\n");
fprintf(fd," rot 0.000000 0.000000 0.000000\n");
fprintf(fd," trans 0.000000 0.000000 0.000000\n");
fprintf(fd," }\n");
fclose(fd);
strcpy(file_name,name);
strcat(file_name,".def");
fd = fopen(file_name,"w");
if ( fd == NULL )
{ perror(file_name);
return;
}
fprintf(fd,"SOFTIMAGE 4D Creative Environment v 1.6 \"ASCII\"\n\n");
fprintf(fd,"PMSH \"%s\"\n {\n ",name);
/* vertex list */
vnumber = (int*)temp_calloc(web.skel[VERTEX].max_ord+1,sizeof(int*));
fprintf(fd," vertex %ld\n",web.skel[VERTEX].count);
n = 1;
FOR_ALL_VERTICES(v_id)
{ REAL *x = get_coord(v_id);
fprintf(fd,"%12d %14.12f %14.12f %14.12f\n",n,
(DOUBLE)x[0],(DOUBLE)x[1],(DOUBLE)x[2]);
vnumber[loc_ordinal(v_id)] = n;
n++;
}
/* triangle list */
fprintf(fd,"\n polygon %ld\n",web.skel[FACET].count);
FOR_ALL_FACETS(f_id)
{ facetedge_id fe = get_facet_fe(f_id);
facetedge_id next_fe = get_next_edge(fe);
int oh = vnumber[loc_ordinal(get_fe_headv(fe))];
fprintf(fd," %10d %10d %10d %10d\n",oh,
vnumber[loc_ordinal(get_fe_headv(next_fe))],
vnumber[loc_ordinal(get_fe_tailv(fe))],
vnumber[loc_ordinal(get_fe_tailv(fe))]);
}
fprintf(fd," }\n\n");
fclose(fd);
temp_free((char*)vnumber);
}
evolver-2.30c.dfsg/src/evaltree.c 0000644 0001753 0001753 00000625721 11410765113 017205 0 ustar hazelsct hazelsct /************************************************************
* This file is part of the Surface Evolver source code. *
* Programmer: Ken Brakke, brakke@susqu.edu *
************************************************************/
/*****************************************************************
*
* File: evaltree.c
*
* Purpose: To execute expression and command trees.
* Tree nodes are stored in postorder linear form
* for fast postorder execution.
*
*/
#include "include.h"
#include "ytab.h"
/* for breakpoints */
#define BREAKMAX 100
struct breakinfo { int name_id; int line; } breaklist[BREAKMAX];
int breakcount;
struct eval_frame *subshell_frame[100];
/*****************************************************************
*
* Function eval()
*
* Purpose: runtime evaluation of expressions and commands.
* The big switch statement is split between two functions to
* get functions small enough for DOS compilers. All nodes
* manipulating the stack are in the eval() function, and
* others in other_stuff(). This should not impose any speed
* penalty on expressions.
*
* Notes: The evaluation stack is a local variable, to permit
* parallel evaluations on shared memory machines. To prevent
* eval() from getting too long, many cases have been moved
* to evalmore(), which is called by the default case of eval().
* But for efficiency, most frequently evaluated cases should
* be in eval().
*
* Uses one permanent stack per thread. Recursive calls to eval()
* wind up using same stack (but progressively, of course).
*/
int current_debug_line;
int debugging_flag;
/* Number of stack slots occupied by a frame structure */
#define FRAME_SPACE ((int)((sizeof(struct eval_frame)+sizeof(REAL)-1)/sizeof(REAL)))
REAL eval ARGS4((ex_original,params,self_id,parent_frame),
struct expnode *ex_original, /* expression tree */
REAL *params, /* vector of parameters */
element_id self_id, /* reference element, if any */
struct eval_frame *parent_frame) /* not used anymore */
{
struct treenode *node; /* currently executing node */
struct thread_data *td = GET_THREAD_DATA;
#define newstack (td->eval_stack)
#define stackmax (td->eval_stack_size)
#define stacktop (td->stack_top)
#define this_frame ((struct eval_frame*)(newstack + td->frame_spot))
int entry_flag = BASE_OF_EVAL; /* so can set frame flag marking entry to eval() */
/* variables that act like registers for stack gymnastics */
struct expnode *ex = ex_original;
struct locallist_t *localbase;
int localcount;
element_id q_id = self_id; /* innermost loop element */
REAL return_value;
struct treenode *return_node = NULL;
REAL *localstack; /* base of local stack, after frame structure */
/* miscellaneous local variables useful in executing nodes */
int k,n,i;
REAL x,y;
element_id id;
REAL *bins;
REAL hi;
REAL lo;
REAL val;
int old_flag = iterate_flag;
facet_id f_id;
REAL vect[MAXCOORD];
facetedge_id fe;
vertex_id v_id;
int recalc_flag = 0;
int update_display_flag = 0;
struct boundary *bdry;
REAL *histo_data;
int histo_max;
int histo_count;
struct global *g;
int oldquiet;
int eval_elapsed_time[2];
if ( ex == NULL ) return 0.0;
if ( ex->start == NULL )
{ sprintf(errmsg,"Trying to evaluate null expression for %s.\n",ex->name);
kb_error(1253,errmsg,WARNING);
return 0.0;
}
PROF_EVAL_START(ex);
if ( !breakflag ) iterate_flag = 2; /* for interrupt handler */
if ( ex->start[1].type != SETUP_FRAME_ )
kb_error(3987,"no frame setup\n",RECOVERABLE);
for ( node = ex->start+1 ; ; node++ )
{
if ( single_step_debugging && (node->line_no != current_debug_line) )
{ char prompt_string[100];
current_debug_line = node->line_no;
subshell_depth++;
subshell_frame[subshell_depth] = this_frame;
setjmp(jumpbuf[subshell_depth]);
if ( subshell_depth == 1 )
sprintf(prompt_string,"Debug (\"%s\" line %d): ",ex->name,node->line_no);
else
{ sprintf(prompt_string,"Debug command(%d): ",subshell_depth);
}
/* command read and execute loop */
debugging_flag = 1;
single_step_debugging = 0;
exec_commands(NULL,prompt_string);
subshell_depth--;
debugging_flag = 0;
}
else
/* have reached node set to a breakpoint */
if ( node->flags & BREAKPOINT_NODE )
{ char prompt_string[100];
current_debug_line = node->line_no;
subshell_depth++;
subshell_frame[subshell_depth] = this_frame;
setjmp(jumpbuf[subshell_depth]);
if ( subshell_depth == 1 )
sprintf(prompt_string,"Debug (\"%s\" line %d): ",ex->name,node->line_no);
else
{ sprintf(prompt_string,"Debug command(%d): ",subshell_depth);
}
/* command read and execute loop */
debugging_flag = 1;
exec_commands(NULL,prompt_string);
subshell_depth--;
debugging_flag = 0;
}
switch ( node->type )
{
struct treenode *where,*enode,*eroot;
case SETUP_FRAME_: /* first node of any procedure */
{ int parent_frame_spot;
int stackused = stacktop-newstack;
/* check stack space */
localbase = ex->locals;
if ( ex->locals )
localcount = ex->locals->totalsize;
else localcount = 0;
if ( stackmax < stackused + localcount + ex->stack_max + FRAME_SPACE + 20 )
{
stackmax = stackused + localcount + ex->stack_max + FRAME_SPACE + 300;
newstack = (REAL*)realloc(newstack,stackmax*sizeof(REAL) );
stacktop = newstack + stackused;
newstack[stackmax-1] = STACKMAGIC; /* sentinel */
}
/* find parent frame, if any */
parent_frame_spot = td->frame_spot;
if ( stacktop == newstack )
parent_frame = NULL;
else
parent_frame = (struct eval_frame*)(newstack + parent_frame_spot);
stacktop++;
/* Set up first frame at current stack position */
td->frame_spot = stacktop - newstack; /* sets this_frame by macro */
stacktop += FRAME_SPACE-1;
this_frame->base_ex = ex;
this_frame->basenode = &node;
this_frame->parent_frame_spot = parent_frame_spot;
td->frame_spot = (REAL*)this_frame - newstack; // redundant?
this_frame->self_id = self_id;
this_frame->return_node = return_node;
this_frame->flags = entry_flag;
entry_flag = 0;
if ( parent_frame )
{ this_frame->flags |= parent_frame->flags & IN_ELEMENT_LOOP;
if ( return_node )
this_frame->flags |= return_node->flags & IN_ELEMENT_LOOP;
}
localstack = stacktop + 1;
/* local variables after frame */
if ( localcount )
{ stacktop++;
memset((char*)stacktop,0,localcount*sizeof(REAL));
stacktop += localcount-1; /* room for local variables */
}
}
break; /* end SETUP_FRAME_ */
case ABORT_:
/*
if ( subshell_depth )
{ exit_flag = 1;
break;
}
*/
breakflag = BREAKABORT;
break;
case SUBCOMMAND_:
{ char prompt_string[100];
char *pmpt;
subshell_depth++;
subshell_frame[subshell_depth] = this_frame;
setjmp(jumpbuf[subshell_depth]);
if ( subshell_depth == 1 )
pmpt = "Subcommand: ";
else
{ sprintf(prompt_string,"Subcommand(%d): ",subshell_depth);
pmpt = prompt_string;
}
/* command read and execute loop */
exec_commands(NULL,pmpt);
subshell_depth--;
break;
}
case SET_BREAKPOINT_:
{ int breakline = (int)(*stacktop--);
struct expnode *proc;
struct treenode *nodespot;
int found = 0;
/* now set flag bit in first node on line */
proc = &(globals(node->op1.name_id)->value.proc);
for ( nodespot = proc->start+1 ; nodespot != proc->root ; nodespot++ )
if ( nodespot->line_no == breakline )
{ nodespot->flags |= BREAKPOINT_NODE;
/* record for unset */
breaklist[breakcount].name_id = node->op1.name_id;
breaklist[breakcount].line = breakline;
breakcount++;
found = 1;
break;
}
if ( !found )
{ sprintf(msg,"Cannot find instruction on line %d of \"%s\".\n",
breakline,&globals(node->op1.name_id)->name);
outstring(msg);
}
break;
}
case UNSET_BREAKPOINT_:
{
struct expnode *proc;
struct treenode *nodespot;
if ( node->left ) /* particular */
{
int breakline = (int)(*stacktop--);
/* unmark breakpoint node */
proc = &(globals(node->op1.name_id)->value.proc);
for ( nodespot = proc->start ; nodespot != proc->root ; nodespot++ )
if ( nodespot->line_no == breakline )
nodespot->flags &= ~BREAKPOINT_NODE;
/* remove from breakpoint list */
for ( i = 0 ; i < breakcount ; i++ )
if ( (breaklist[i].name_id == node->op1.name_id) &&
(breaklist[i].line == breakline) )
{ breaklist[i] = breaklist[--breakcount];
}
}
else /* all */
{
for ( i = 0 ; i < breakcount ; i++ )
{ proc = &(globals(breaklist[i].name_id)->value.proc);
for ( nodespot = proc->start ; nodespot != proc->root ; nodespot++ )
nodespot->flags &= ~BREAKPOINT_NODE;
}
breakcount = 0;
}
break;
}
case WHEREAMI_COMMAND_: /* for use in debugging or subshells */
{ struct eval_frame *frame = subshell_frame[subshell_depth];
while ( frame )
{ sprintf(msg," %s:%d\n",frame->base_ex->name,frame->return_node->line_no);
outstring(msg);
if ( frame->flags & BASE_OF_WHOLE_STACK )
frame = NULL;
else
frame = (struct eval_frame*)(newstack + frame->parent_frame_spot);
};
break;
}
case FREE_DISCARDS_:
if ( (node->flags & IN_ELEMENT_LOOP) ||
( this_frame->flags & IN_ELEMENT_LOOP ) )
kb_error(1904,"free_discards called inside element loop. Ignored.",
WARNING);
else
free_discards(DISCARDS_ALL);
break;
case SINGLE_LETTER_:
if ( debugging_flag && node->op1.letter == 'n' ) /* special for debugging prompt */
{ single_step_debugging = 1;
exit_flag = 1;
goto the_exit;
break;
}
if ( !(node->flags & IN_ELEMENT_LOOP) &&
!(this_frame->flags & IN_ELEMENT_LOOP) )
free_discards(DISCARDS_SOME);
letter_command(node->op1.letter);
break;
case LINEAR_:
if ( web.modeltype == QUADRATIC )
{ quad_to_linear(); recalc(); break; }
else if ( web.modeltype == LAGRANGE )
lagrange_to_linear();
break;
case QUADRATIC_:
if ( !(node->flags & IN_ELEMENT_LOOP) &&
!(this_frame->flags & IN_ELEMENT_LOOP) )
free_discards(DISCARDS_SOME);
if ( web.modeltype == LINEAR )
{ linear_to_quad(); recalc(); break; }
else if ( web.modeltype == LAGRANGE )
lagrange_to_quad();
break;
case LAGRANGE_:
if ( !(node->flags & IN_ELEMENT_LOOP) &&
!(this_frame->flags & IN_ELEMENT_LOOP) )
free_discards(DISCARDS_SOME);
if ( web.modeltype == LINEAR )
linear_to_lagrange((int)(*stacktop--));
else if ( web.modeltype == QUADRATIC )
quad_to_lagrange((int)(*stacktop--));
else
lagrange_to_lagrange((int)(*stacktop--));
break;
case ELINDEX_: /* id possibly with mpi task number */
/* creates typeless valid id */
{ int task;
if ( node->right )
task = (int)(*stacktop--);
else task = this_task;
if ( *stacktop == 0 )
id = NULLID;
else
{ if ( *stacktop > 0.0 )
id = ((int)(*stacktop)-1);
else
{ id = -((int)(*stacktop)+1);
invert(id);
}
id |= VALIDMASK;
}
#ifdef MPI_EVOLVER
if ( task < 0 || task >= mpi_nprocs )
{ sprintf(errmsg,
"Illegal task number %d. Must be between 1 and %d.\n",task,mpi_nprocs);
kb_error(4324,errmsg,RECOVERABLE);
}
id |= (element_id)task << TASK_ID_SHIFT;
#endif
*(element_id *)stacktop = id;
break;
}
case PUSH_ELEMENT_ID_:
*(element_id *)(++stacktop) = node->op1.id;
break;
case VALID_ELEMENT_:
id = get_full_id(node->op1.eltype,*(element_id*)stacktop);
*stacktop = valid_element(id) ? 1.0 : 0.0;
break;
case VALID_CONSTRAINT_:
{ int connum = (int)*stacktop;
if ( (connum<0) || (connum>=web.maxcon) || !(get_constraint(connum)->attr & IN_USE))
*stacktop = 0.0;
else
*stacktop = 1.0;
break;
}
case VALID_BOUNDARY_:
{ int bnum = (int)*stacktop;
if ( (bnum<0) || (bnum>=web.bdrymax) || !(web.boundaries[bnum].attr & IN_USE))
*stacktop = 0.0;
else
*stacktop = 1.0;
break;
}
case LOAD_:
if ( subshell_depth )
{ kb_error(3634,"Can't reload in a subcommand.\n",WARNING);
stacktop--;
break;
}
strncpy(loadfilename,*(char**)(stacktop--),sizeof(loadfilename));
#ifdef __cplusplus
loadstub(); /* indirect throw of exception */
#else
longjmp(loadjumpbuf,1);
#endif
break;
case ADDLOAD_:
{ FILE *newfd;
int old_read_depth;
char *name = *(char**)(stacktop--);
newfd = path_open(name,NOTDATAFILENAME);
if (newfd == NULL)
{ if ( name[0] )
{
sprintf(errmsg,"Cannot open datafile %s.\n",name);
kb_error(5432,errmsg,RECOVERABLE);
}
break; /* continue with old */
}
ENTER_GRAPH_MUTEX;
push_commandfd(newfd,name); /* start #include stack */
datafile_flag = 1; /* so parser knows */
addload_flag = 1;
datafile_input_flag = 1; /* so lex input knows */
cmdptr = 0;
old_read_depth = read_depth;
initialize();
if ( read_depth >= old_read_depth )
pop_commandfd();
datafile_flag = 0;
addload_flag = 0;
if ( fabs(view[0][0])+fabs(view[1][1])+fabs(view[2][2]) < 1e-25 )
resize();
LEAVE_GRAPH_MUTEX;
recalc();
break;
}
case PERMLOAD_: /* keep going with same command */
/* with contortions to preserve current list */
{ struct expnode keeplist;
struct eval_frame *fr;
size_t spot;
if ( subshell_depth )
{ kb_error(3635,"Can't reload in a subcommand.\n",WARNING);
stacktop--;
break;
}
/* make sure all parent frames permanent (except very first frame
corresponding to original user command */
for ( fr = this_frame; fr != NULL ;
fr = (struct eval_frame*)(newstack + this_frame->parent_frame_spot) )
{ if ( !(fr->flags & BASE_OF_WHOLE_STACK) && !(fr->base_ex->start->flags & PERMNODE) )
{ strcpy(errmsg, "Calling permload in non-permanent command.\n");
sprintf(errmsg+strlen(errmsg),"(source file %s, line %d)\n",
file_names[node->file_no],node->line_no);
kb_error(3364,errmsg, RECOVERABLE);
}
if ( fr->flags & BASE_OF_WHOLE_STACK ) break;
}
if ( !(fr->base_ex->start->flags & PERMNODE) )
{ /* have to kludge to preserve current command list */
memset(&keeplist,0,sizeof(keeplist));
perm_tree_copy(&keeplist,fr->base_ex->root);
spot = (*(fr->basenode) - (fr->base_ex->start));
*(fr->basenode) = keeplist.start + spot;
memset(fr->base_ex,0,sizeof(struct expnode)); /* so doesn't do free_expr()later */
fr->base_ex = &keeplist;
}
strncpy(loadfilename,*(char**)(stacktop--),sizeof(loadfilename));
startup(loadfilename);
exec_commands(commandfd,"Enter command: "); /* from end of datafile */
/* keeplist permanently allocated, but we'll live with memory leak
as price for not doing shenanigans every eval() just to avoid leak. */
}
break;
case FUNCTION_CALL_:
{ struct global *g = globals(node->op1.name_id);
if ( g->value.proc.root == NULL )
{ sprintf(errmsg,
"Function \"%s\" definition has not been executed yet.\n",g->name);
sprintf(errmsg+strlen(errmsg),"(source file %s, line %d)\n",
file_names[node->file_no],node->line_no);
kb_error(2621,errmsg,RECOVERABLE);
}
PROF_EVAL_END(ex);
ex = &g->value.proc;
PROF_EVAL_START(ex);
return_node = node;
node = g->value.proc.start;
break;
}
case FUNCTION_CALL_RETURN_:
{
stacktop -= node->op2.argcount; /* pop arguments */
*(++stacktop) = return_value;
break;
}
case PROCEDURE_CALL_: /* with arguments */
{ struct global *g = globals(node->op1.name_id);
if ( g->value.proc.root == NULL )
{ sprintf(errmsg,
"Procedure \"%s\" definition has not been executed yet.\n",g->name);
sprintf(errmsg+strlen(errmsg),"(source file %s, line %d)\n",
file_names[node->file_no],node->line_no);
kb_error(2622,errmsg,RECOVERABLE);
}
PROF_EVAL_END(ex);
ex = &g->value.proc;
PROF_EVAL_START(ex);
return_node = node;
node = g->value.proc.start;
break;
}
case PROCEDURE_CALL_RETURN_:
stacktop -= node->op2.argcount; /* pop arguments */
break;
case PROCEDURE_:
PROF_EVAL_END(ex);
eval(&globals(node->op1.name_id)->value.proc,NULL,NULLID,NULL);
PROF_EVAL_START(ex);
break;
case PERM_PROCEDURE_:
PROF_EVAL_END(ex);
eval(&perm_globals(node->op1.name_id)->value.proc,NULL,NULLID,NULL);
PROF_EVAL_START(ex);
break;
case CMDLIST_: case COMMAND_BLOCK_:
/* no action, just holds tree together */
break;
case DECLARE_LOCAL_: break;
case LOCAL_LIST_START_: break;
case SINGLE_REDEFD_:
if ( single_redefine[node->op1.letter].start )
{
PROF_EVAL_END(ex);
eval(&single_redefine[node->op1.letter],NULL,NULLID,NULL);
PROF_EVAL_START(ex);
}
else letter_command(node->op1.letter);
break;
case MATRIX_INVERSE_:
{ REAL *datastart2 = *(REAL**)(stacktop--);
REAL *datastart1 = *(REAL**)(stacktop--);
struct array *a = get_name_arrayptr(node->op1.name_id,localstack,localbase);
struct array *b = get_name_arrayptr(node->op2.name_id,localstack,localbase);
*(++stacktop) = (REAL)matrix_inverse_command(a,
b,datastart1,datastart2);
}
break;
case MATRIX_MULTIPLY_:
{ REAL *datastart3 = *(REAL**)(stacktop--);
REAL *datastart2 = *(REAL**)(stacktop--);
REAL *datastart1 = *(REAL**)(stacktop--);
struct array *a = get_name_arrayptr(node->op1.name_id,localstack,localbase);
struct array *b = get_name_arrayptr(node->op2.name_id,localstack,localbase);
struct array *c = get_name_arrayptr(node->op3.name_id,localstack,localbase);
matrix_multiply_command(a,b,c,datastart1,datastart2,datastart3);
}
break;
case MATRIX_DETERMINANT_:
{ REAL *datastart1 = *(REAL**)(stacktop--);
struct array *a = get_name_arrayptr(node->op1.name_id,localstack,localbase);
*(++stacktop) = matrix_determinant_command(a,datastart1);
}
break;
case BACKQUOTE_START_:
{ struct expnode bqnode = *ex;
bqnode.start = node;
bqnode.root = node+node->op1.skipsize;
bqnode.locals = localbase;
PROF_EVAL_END(ex);
eval(&bqnode,params,self_id,this_frame);
PROF_EVAL_START(ex);
node += node->op1.skipsize-1; /* skip what was evaluated */
}
break;
case BACKQUOTE_END_ : break; /* just a placeholder */
case ACOMMANDEXPR_: /* backquoted command at start of expression */
break;
case INDEXSET_: break; /* just accumulate index values */
case DIMENSIONSET_: break; /* just accumulate index values */
case DEFINE_FIXED_LOCAL_ARRAY_: break; /* was allocated on stack */
case SHOW_:
case SHOW_EXPR_:
{ int etype; /* element type */
where = node + node->op1.skipsize;
if ( where->type == WHERE_ ) /* condition */
{ /* copy over expression */
enode = where + where->left; /* NEXT */
eroot = where + where->right;
etype = enode[enode->left].op1.eltype;
show_expr[etype] = show_expr_table + etype;
tree_copy(show_expr[etype],eroot);
sprintf(show_expr[etype]->name,"show expression for %s.",
typenames[etype]);
/* can use first slot to record type of element */
/* element location */
show_expr[etype]->start->op2.eltype = enode->op2.eltype;
enode += enode->left; /* INIT */
show_expr[etype]->start->op1.eltype = enode->op1.eltype;
show_expr[etype]->locals = (struct locallist_t*)mycalloc(1,sizeof(struct locallist_t));
*(show_expr[etype]->locals) = *(ex->locals);
}
else
{ etype = where[where->left].op1.eltype;
tree_copy(show_expr[etype],NULL);
show_expr[etype] = NULL;
}
/* save for dump */
tree_copy(show_command+etype,node+node->op1.skipsize+1);
if ( (node->type == SHOW_) && !OOGL_flag && !go_display_flag)
do_show();
else update_display();
node += node->op1.skipsize; /* skip over expression */
break;
}
case UNREDEFINE_SINGLE_:
free_expr(&single_redefine[node->op1.letter]);
break;
case REDEFINE_SINGLE_:
tree_copy(&single_redefine[node->op1.letter],node+node->op2.jumpsize);
sprintf(single_redefine[node->op1.letter].name,"redefined command '%c'",
node->op1.letter);
single_redefine[node->op1.letter].flag = USERCOPY;
locals_copy(&(single_redefine[node->op1.letter].locals),
node->op5.locals);
node += node->op2.jumpsize; /* skip over procedure */
break;
case SET_PROCEDURE_:
g = globals(node->op1.name_id);
free_expr(&g->value.proc);
tree_copy(&g->value.proc, node+node->op2.jumpsize);
strcpy(g->value.proc.name, g->name);
g->attr.procstuff.proc_timestamp = proc_timestamp++;
locals_copy(&(g->value.proc.locals),node->op5.locals);
node += node->op2.jumpsize; /* skip over procedure */
break;
case SET_PERM_PROCEDURE_:
g = perm_globals(node->op1.name_id);
perm_free_expr(&g->value.proc);
perm_tree_copy(&g->value.proc, node+node->op2.jumpsize);
strcpy(g->value.proc.name, g->name);
g->attr.procstuff.proc_timestamp = proc_timestamp++;
locals_copy_perm(&(g->value.proc.locals),node->op5.locals);
node += node->op2.jumpsize; /* skip over procedure */
break;
case SET_FUNCTION_: break;
case FUNCTION_HEAD_ : break;
case ARGLIST_ : break;
case FUNCTION_DEF_START_ :
g = globals(node->op1.name_id);
free_expr(&g->value.proc);
tree_copy(&g->value.proc, node+node->op2.jumpsize);
g->value.proc.start[2].type = FUNCTION_START_;
strcpy(g->value.proc.name, g->name);
g->attr.procstuff.proc_timestamp = proc_timestamp++;
locals_copy(&(g->value.proc.locals),node->op5.locals);
node += node->op2.jumpsize; /* skip over procedure */
break;
case FUNCTION_PROTO_START_:
node += node->op2.jumpsize; /* skip over stuff */
break;
case FUNCTION_START_: /* function entry code */
/* copy arguments over to local variable space */
memcpy((char*)(stacktop-localcount+1),
(char*)(((REAL*)this_frame)-node->op3.argcount),
node->op3.argcount*sizeof(REAL));
break;
case SET_ARGSPROC_: break;
case PROCEDURE_HEAD_ : break;
case PROCEDURE_DEF_START_ :
g = globals(node->op1.name_id);
free_expr(&g->value.proc);
tree_copy(&g->value.proc, node+node->op2.jumpsize);
g->value.proc.start[2].type = PROCEDURE_START_;
strcpy(g->value.proc.name, g->name);
g->attr.procstuff.proc_timestamp = proc_timestamp++;
locals_copy(&(g->value.proc.locals),node->op5.locals);
node += node->op2.jumpsize; /* skip over procedure */
break;
case PROCEDURE_PROTO_START_:
node += node->op2.jumpsize; /* skip over stuff */
break;
case PROCEDURE_START_: /* function entry code */
/* copy arguments over to local variable space */
if ( node->op3.argcount )
memcpy((char*)(stacktop-localcount+1),
(char*)(((REAL*)this_frame)-node->op3.argcount),
node->op3.argcount*sizeof(REAL));
break;
case RETURN_:
if ( node->left )
{ localstack[localbase->totalsize] = *stacktop;
stacktop = localstack + localbase->totalsize;
}
else
stacktop = localstack + localbase->totalsize - 1;
node = ex->root; /* since next node should be FINISHED */
if ( node[1].type != FINISHED )
kb_error(4578,"Internal error: no FINISH node after RETURN\n", RECOVERABLE);
break;
/********************/
/* repeated command */
/********************/
case REPEAT_INIT_:
/* target on stack, then iteration count */
gocount = (int)*stacktop;
*(++stacktop) = 0; /* iterations done */
if ( gocount <= 0 )
{ stacktop -= 2; /* pop counts */
node += node->op1.skipsize; /* skip loop */
gocount = 1;
}
break;
case REPEAT_:
{ struct treenode *rnode = node + node->left;
stacktop[0] += 1;
gocount = (int)(stacktop[-1] - stacktop[0]);
#if defined(MAC_APP) || defined(MAC_CW)
break_check();
#endif
if ( breakflag )
{ stacktop -= 2; breakflag = 0; break; }
if ( (gocount > 0) && !breakflag )
{ node = rnode; /* do again */
/* loop increment will step over REPEAT_INIT_ node */
}
else
{ stacktop -= 2; /* pop gocount and total count */
gocount = 1; /* so prints as 1 when no count given */
}
}
break;
/*******************/
/* flow of control */
/*******************/
case IFTEST_:
case COND_TEST_:
if ( *(stacktop--) == 0. )
{ /* jump */
node += node->op1.skipsize;
}
break;
case IF_:
case COND_EXPR_:
/* did first command, so skip second */
node += node->op1.skipsize;
break;
case CONTINUE_:
node += node->op1.skipsize; /* back to loop top */
stacktop = localstack + *(size_t*)(localstack+node->stackpos);
node += node->op4.contjump; /* jump to expr */
break;
case BREAK_:
node += node->op1.skipsize; /* back to loop top */
stacktop = localstack + *(size_t*)(localstack+node->stackpos);
node += node->op3.breakjump; /* jump to end */
break;
case WHILE_TOP_:
/* break and continue jumps */
*(size_t*)(localstack + node->stackpos) = stacktop - localstack - 1;
/* jumptest if expr false */
if ( (*(stacktop--) == 0.) || breakflag )
node += node->op1.skipsize;
break;
case WHILE_END_:
/* loop back */
node += node->op1.skipsize;
break;
case DO_TOP_:
/* break and continue jumps */
*(size_t*)(localstack + node->stackpos) = stacktop - localstack;
break;
case DO_ENTRY_:
/* break and continue jumps */
*(size_t*)(localstack + node->stackpos) = stacktop - localstack;
break;
case DO_END_:
/* loop back if true */
if ( *(stacktop--) && !breakflag )
node += node->op1.skipsize;
break;
case FOR_ENTRY_:
/* break and continue jumps */
*(size_t*)(localstack + node->stackpos) = stacktop - localstack;
break;
case FOR_HEAD_:
if ( *(stacktop--) && !breakflag )
node += node->op1.skipsize; /* loop body */
else
node += node->op2.jumpsize; /* break out of loop */
break;
case FOR_TOP_:
node += node->op1.skipsize; /* jump to test expr */
break;
case FOR_END_:
node += node->op1.skipsize; /* jump to increment command */
break;
/*******************/
/* aggregate verbs */
/*******************/
case LIST_:
oldquiet = quiet_flag; quiet_flag = 0;
switch ( node->op2.eltype )
{
case VERTEX:
vertex_dump(positive_id(q_id),outfd);
break;
case EDGE:
edge_dump(positive_id(q_id),outfd);
break;
case FACET:
facet_dump(positive_id(q_id),outfd);
break;
case BODY:
body_dump(positive_id(q_id),outfd);
break;
case FACETEDGE:
facetedge_dump(positive_id(q_id),outfd);
break;
default:
sprintf(errmsg,"Bad LIST element type in %s.\n",ex->name);
sprintf(errmsg+strlen(errmsg),"(source file %s, line %d)\n",
file_names[node->file_no],node->line_no);
quiet_flag = oldquiet;
kb_error(1255,errmsg,RECOVERABLE);
}
quiet_flag = oldquiet;
node += node->op1.skipsize - 1; /* back to start of loop */
break;
/***********************
* commands with counts *
***********************/
case REFINE_:
switch ( node->op2.eltype )
{
case EDGE:
n = valid_id(edge_refine(q_id));
if ( web.counts_reported & edge_refine_count_bit )
{ web.edge_refine_count = 0;
web.counts_reported &= ~edge_refine_count_bit;
}
if ( n )
{ web.edge_refine_count += n;
web.counts_changed |= edge_refine_count_bit;
recalc_flag = 1;
}
break;
case FACET:
face_triangulate(q_id,FACET_EDGES);
n = 1;
if ( web.counts_reported & facet_refine_count_bit )
{ web.facet_refine_count = 0;
web.counts_reported &= ~facet_refine_count_bit;
}
if ( n )
{ web.facet_refine_count += n;
web.counts_changed |= facet_refine_count_bit;
recalc_flag = 1;
}
break;
default:
sprintf(errmsg,"Bad refine element type in %s.\n",ex->name);
sprintf(errmsg+strlen(errmsg),"(source file %s, line %d)\n",
file_names[node->file_no],node->line_no);
kb_error(1256,errmsg, RECOVERABLE);
}
node += node->op1.skipsize - 1; /* back to start of loop */
break;
case POP_:
n = 0;
if ( id_type(q_id) == EDGE )
{ n = pop_one_edge(q_id);
if ( web.counts_reported & edge_pop_count_bit )
{ web.edge_pop_count = 0;
web.counts_reported &= ~edge_pop_count_bit;
}
if ( n )
{ web.edge_pop_count += n;
web.counts_changed |= edge_pop_count_bit;
}
}
else if ( id_type(q_id) == VERTEX )
{ n = pop_given_vertex(q_id);
if ( web.counts_reported & vertex_pop_count_bit )
{ web.vertex_pop_count = 0;
web.counts_reported &= ~vertex_pop_count_bit;
}
if ( n )
{ web.vertex_pop_count += n;
web.counts_changed |= vertex_pop_count_bit;
}
}
else
{ sprintf(errmsg,"Only vertices and edges poppable.\n");
sprintf(errmsg+strlen(errmsg),"(source file %s, line %d)\n",
file_names[node->file_no],node->line_no);
kb_error(3356,errmsg, RECOVERABLE);
}
node += node->op1.skipsize - 1; /* back to start of loop */
if ( n ) recalc_flag = 1;
break;
case POP_TRI_TO_EDGE_:
n = pop_tri_to_edge(q_id);
if ( web.counts_reported & pop_tri_to_edge_count_bit )
{ web.pop_tri_to_edge_count = 0;
web.counts_reported &= ~pop_tri_to_edge_count_bit;
}
if ( n )
{ web.pop_tri_to_edge_count += n;
web.counts_changed |= pop_tri_to_edge_count_bit;
}
node += node->op1.skipsize - 1; /* back to start of loop */
if ( n ) recalc_flag = 1;
break;
case POP_EDGE_TO_TRI_:
n = pop_edge_to_tri(q_id);
if ( web.counts_reported & pop_edge_to_tri_count_bit )
{ web.pop_edge_to_tri_count = 0;
web.counts_reported &= ~pop_edge_to_tri_count_bit;
}
if ( n )
{ web.pop_edge_to_tri_count += n;
web.counts_changed |= pop_edge_to_tri_count_bit;
}
node += node->op1.skipsize - 1; /* back to start of loop */
if ( n ) recalc_flag = 1;
break;
case POP_QUAD_TO_QUAD_:
n = pop_quad_to_quad(q_id);
if ( web.counts_reported & pop_quad_to_quad_count_bit )
{ web.pop_quad_to_quad_count = 0;
web.counts_reported &= ~pop_quad_to_quad_count_bit;
}
if ( n )
{ web.pop_quad_to_quad_count += n;
web.counts_changed |= pop_quad_to_quad_count_bit;
}
node += node->op1.skipsize - 1; /* back to start of loop */
if ( n ) recalc_flag = 1;
break;
case EDGESWAP_:
n = edgeswap(q_id);
if ( web.counts_reported & edgeswap_count_bit )
{ web.edgeswap_count = 0;
web.counts_reported &= ~edgeswap_count_bit;
}
if ( n )
{ web.edgeswap_count += n;
web.counts_changed |= edgeswap_count_bit;
}
node += node->op1.skipsize - 1; /* back to start of loop */
if ( n ) recalc_flag = 1;
break;
case T1_EDGESWAP_:
n = t1_edgeswap(q_id);
if ( web.counts_reported & t1_edgeswap_count_bit )
{ web.t1_edgeswap_count = 0;
web.counts_reported &= ~t1_edgeswap_count_bit;
}
if ( n )
{ web.t1_edgeswap_count += n;
web.counts_changed |= t1_edgeswap_count_bit;
}
node += node->op1.skipsize - 1; /* back to start of loop */
if ( n ) recalc_flag = 1;
break;
case EQUIANGULATE_:
n = equiangulate_edge(q_id);
if ( web.counts_reported & equi_count_bit )
{ web.equi_count = 0;
web.counts_reported &= ~equi_count_bit;
}
if ( n )
{ web.equi_count += n;
web.counts_changed |= equi_count_bit;
}
node += node->op1.skipsize - 1; /* back to start of loop */
if ( n ) recalc_flag = 1;
break;
case DISSOLVE_:
switch ( node->op2.eltype )
{ case VERTEX:
n = dissolve_vertex(q_id);
if ( web.counts_reported & vertex_dissolve_count_bit )
{ web.vertex_dissolve_count = 0;
web.counts_reported &= ~vertex_dissolve_count_bit;
}
if ( n )
{ web.vertex_dissolve_count += n;
web.counts_changed |= vertex_dissolve_count_bit;
recalc_flag = 1;
}
break;
case EDGE:
n = dissolve_edge(q_id);
if ( web.counts_reported & edge_dissolve_count_bit )
{ web.edge_dissolve_count = 0;
web.counts_reported &= ~edge_dissolve_count_bit;
}
if ( n )
{ web.edge_dissolve_count += n;
web.counts_changed |= edge_dissolve_count_bit;
recalc_flag = 1;
}
break;
case FACET:
n = dissolve_facet(q_id);
if ( web.counts_reported & facet_dissolve_count_bit )
{ web.facet_dissolve_count = 0;
web.counts_reported &= ~facet_dissolve_count_bit;
}
if ( n )
{ web.facet_dissolve_count += n;
web.counts_changed |= facet_dissolve_count_bit;
recalc_flag = 1;
}
break;
case BODY:
n = dissolve_body(q_id);
if ( web.counts_reported & body_dissolve_count_bit )
{ web.body_dissolve_count = 0;
web.counts_reported &= ~body_dissolve_count_bit;
}
if ( n )
{ web.body_dissolve_count += n;
web.counts_changed |= body_dissolve_count_bit;
recalc_flag = 1;
}
break;
}
node += node->op1.skipsize - 1; /* back to start of loop */
break;
case REVERSE_ORIENTATION_:
switch ( node->op2.eltype )
{
case EDGE:
reverse_orientation_edge(q_id);
if ( web.counts_reported & edge_reverse_count_bit )
{ web.edge_reverse_count = 0;
web.counts_reported &= ~edge_reverse_count_bit;
}
web.edge_reverse_count += 1;
web.counts_changed |= edge_reverse_count_bit;
recalc_flag = 1;
break;
case FACET:
reverse_orientation_facet(q_id);
if ( web.counts_reported & facet_reverse_count_bit )
{ web.facet_reverse_count = 0;
web.counts_reported &= ~facet_reverse_count_bit;
}
web.facet_reverse_count += 1;
web.counts_changed |= facet_reverse_count_bit;
recalc_flag = 1;
break;
}
node += node->op1.skipsize - 1; /* back to start of loop */
break;
case FIX_:
if ( web.counts_reported & fix_count_bit )
{ web.fix_count = 0;
web.counts_reported &= ~fix_count_bit;
}
if ( !(get_attr(q_id)&FIXED) )
{ set_attr(q_id,FIXED);
web.fix_count += 1;
web.counts_changed |= fix_count_bit;
}
node += node->op1.skipsize - 1; /* back to start of loop */
break;
case UNFIX_:
if ( web.counts_reported & unfix_count_bit )
{ web.unfix_count = 0;
web.counts_reported &= ~unfix_count_bit;
}
if ( get_attr(q_id) & FIXED )
{ unset_attr(q_id,FIXED);
web.unfix_count += 1;
web.counts_changed |= unfix_count_bit;
}
node += node->op1.skipsize - 1; /* back to start of loop */
break;
case VERTEX_AVERAGE_:
if ( new_vertex_average(q_id,VOLKEEP) ) recalc_flag = 1;
node += node->op1.skipsize - 1; /* back to start of loop */
break;
case RAW_VERTEX_AVERAGE_:
if ( new_vertex_average(q_id,NOVOLKEEP) ) recalc_flag = 1;
node += node->op1.skipsize - 1; /* back to start of loop */
break;
case RAWEST_VERTEX_AVERAGE_:
if ( new_vertex_average(q_id,RAWEST) ) recalc_flag = 1;
node += node->op1.skipsize - 1; /* back to start of loop */
break;
case DELETE_:
switch ( node->op2.eltype )
{
case EDGE:
n = eliminate_edge(q_id);
if ( n ) free_element(q_id);
if ( web.counts_reported & edge_delete_count_bit )
{ web.edge_delete_count = 0;
web.counts_reported &= ~edge_delete_count_bit;
}
if ( n )
{ web.edge_delete_count += n;
web.counts_changed |= edge_delete_count_bit;
recalc_flag = 1;
}
break;
case FACET:
n = eliminate_facet(q_id);
if ( web.counts_reported & facet_delete_count_bit )
{ web.facet_delete_count = 0;
web.counts_reported &= ~facet_delete_count_bit;
}
if ( n > 0 )
{ web.facet_delete_count += n;
web.counts_changed |= facet_delete_count_bit;
recalc_flag = 1;
}
if ( n < 0 ) /* from string_eliminate_edge, partial elim */
{ web.edge_delete_count += -n;
web.counts_reported &= ~edge_delete_count_bit;
recalc_flag = 1;
}
break;
default:
sprintf(errmsg,"Bad delete element type in %s.\n",ex->name);
sprintf(errmsg+strlen(errmsg),"(source file %s, line %d)\n",
file_names[node->file_no],node->line_no);
kb_error(1257,errmsg, RECOVERABLE);
}
node += node->op1.skipsize - 1; /* back to start of loop */
break;
/***************/
/* expressions */
/***************/
case REPLACECONST:
*stacktop = node->op1.real;
break;
case PUSHCONST:
*++stacktop = node->op1.real;
break;
case PUSHDELTA_:
{ struct global *g = globals(node->op1.name_id);
*++stacktop = g->attr.varstuff.delta;
break;
}
case PUSH_PARAM_SCALE:
{ struct global *g = globals(node->op1.name_id);
*++stacktop = g->attr.varstuff.pscale;
break;
}
case PUSH_PARAM_FIXED:
{ struct global *g = globals(node->op1.name_id);
*++stacktop = (g->flags & OPTIMIZING_PARAMETER)?0.0:1.0;
break;
}
case PUSH_PARAM_EXTRA_:
{ int i;
for ( i = 0 ; i < optparamcount ; i++ )
if ( optparam[i].pnum == node->op1.name_id )
{ switch ( node->op2.extranum )
{ case V_VELOCITY_ATTR:
*++stacktop = optparam[i].velocity;
break;
case V_FORCE_ATTR:
*++stacktop = optparam[i].grad;
break;
}
break;
}
if ( i == optparamcount ) *++stacktop = 0.0;
break;
}
case PUSHGLOBAL_:
case STRINGGLOBAL_:
case PUSH_PERM_GLOBAL_:
case PERM_STRINGGLOBAL_:
{ struct global *g = globals(node->op1.name_id);
if ( g->flags & GLOB_LOCALVAR )
*++stacktop = localstack[g->value.offset];
else if ( g->flags & FILE_VALUES )
*++stacktop = g->value.file.values[int_val];
else if ( g->flags & STRINGVAL )
{ int pp = (sizeof(REAL)+sizeof(char*)-1)/sizeof(char*);
int nn;
stacktop++;
for ( nn = 0 ; nn < pp ; nn++ )
((char **)stacktop)[nn] = g->value.string;
}
else if ( g->flags & INTERNAL_NAME )
{ if ( g->flags & INTVAL )
*++stacktop = *(int*)(g->value.dataptr);
else if ( g->flags & REALVAL )
*++stacktop = *(REAL*)(g->value.dataptr);
else
{ sprintf(errmsg,
"Internal error: Internal variable %s type not set.\n",g->name);
kb_error(2851,errmsg,RECOVERABLE);
}
}
else
*++stacktop = g->value.real;
}
break;
case PUSHPI:
*++stacktop = M_PI;
break;
case PUSHE:
*++stacktop = M_E;
break;
case PUSHG:
*++stacktop = web.gravflag ? web.grav_const : 0.0;
break;
case PUSHPARAM:
*++stacktop = params[node->op1.coordnum];
break;
case USERFUNC:
*++stacktop = (*userfunc[node->op1.userfunc])(params);
break;
case DYNAMIC_LOAD_FUNC_:
if ( ! params )
{ sprintf(errmsg,
"Must use dynamic load function %s in context with parameters.\n",
globals(node->op2.name_id)->name);
sprintf(errmsg+strlen(errmsg),"(source file %s, line %d)\n",
file_names[node->file_no],node->line_no);
kb_error(2059,errmsg,RECOVERABLE);
} else
(*node->op1.funcptr)(FUNC_VALUE,params,(struct dstack*)(++stacktop));
break;
case GT_:
stacktop--;
stacktop[0] = (REAL)(stacktop[0] > stacktop[1]);
break;
case LT_:
stacktop--;
stacktop[0] = (REAL)(stacktop[0] < stacktop[1]);
break;
case LE_:
stacktop--;
stacktop[0] = (REAL)(stacktop[0] <= stacktop[1]);
break;
case GE_:
stacktop--;
stacktop[0] = (REAL)(stacktop[0] >= stacktop[1]);
break;
case NE_:
stacktop--;
stacktop[0] = (REAL)(stacktop[0] != stacktop[1]);
break;
case EQ_:
stacktop--;
stacktop[0] = (REAL)(stacktop[0] == stacktop[1]);
break;
case AND_: /* short-circuit */
if ( *stacktop == 0.0 )
{ *(++stacktop) = 0.0;
node += node->op1.skipsize; /* leave 0 as result */
}
break;
case CONJUNCTION_END:
/* short-circuiting results in second arg being answer */
/* get proper 1 for true */
stacktop--;
*stacktop = stacktop[1];
if ( *stacktop ) *stacktop = 1.0;
break;
case OR_: /* short-circuit */
if ( *stacktop != 0.0 )
{ *(++stacktop) = 1.0;
node += node->op1.skipsize; /* leave as result */
}
break;
case NOT_:
stacktop[0] = (REAL)(!stacktop[0]);
break;
case PLUS:
stacktop--;
stacktop[0] += stacktop[1];
break;
case MINUS:
case EQUATE:
stacktop--;
stacktop[0] -= stacktop[1];
break;
case TIMES:
stacktop--;
stacktop[0] *= stacktop[1];
break;
case DIVIDE:
stacktop--;
if ( stacktop[1] == 0.0 )
{ if ( valid_id(self_id) )
sprintf(errmsg,"Division by zero in %s, %s %s.\n",ex->name,
typenames[id_type(self_id)],ELNAME(self_id));
else sprintf(errmsg,"Division by zero in %s.\n",ex->name);
sprintf(errmsg+strlen(errmsg),"(source file %s, line %d)\n",
file_names[node->file_no],node->line_no);
kb_error(1258,errmsg,RECOVERABLE);
}
stacktop[0] /= stacktop[1];
break;
case REALMOD:
stacktop--;
if ( stacktop[1] == 0.0 )
{ if ( valid_id(self_id) )
sprintf(errmsg,"Modulus base zero in %s, %s %s.\n",ex->name,
typenames[id_type(self_id)],ELNAME(self_id));
else sprintf(errmsg,"Modulus base zero in %s.\n",ex->name);
sprintf(errmsg+strlen(errmsg),"(source file %s, line %d)\n",
file_names[node->file_no],node->line_no);
kb_error(1259,errmsg,RECOVERABLE);
}
stacktop[0] = stacktop[0] - floor(stacktop[0]/stacktop[1])
*stacktop[1];
break;
case IMOD_:
stacktop--;
if ( stacktop[1] == 0.0 )
{ if ( valid_id(self_id) )
sprintf(errmsg,"Modulus base zero in %s, %s %s.\n",ex->name,
typenames[id_type(self_id)],ELNAME(self_id));
else sprintf(errmsg,"Modulus base zero in %s.\n",ex->name);
sprintf(errmsg+strlen(errmsg),"(source file %s, line %d)\n",
file_names[node->file_no],node->line_no);
kb_error(1260,errmsg,RECOVERABLE);
}
stacktop[0] = floor(stacktop[0]) -
floor(floor(stacktop[0])/floor(stacktop[1]))
*floor(stacktop[1]);
break;
case IDIV_:
stacktop--;
if ( (int)stacktop[1] == 0 )
{ if ( valid_id(self_id) )
sprintf(errmsg,"Division by zero in %s, %s %s.\n",ex->name,
typenames[id_type(self_id)],ELNAME(self_id));
else sprintf(errmsg,"Division by zero in %s.\n",ex->name);
sprintf(errmsg+strlen(errmsg),"(source file %s, line %d)\n",
file_names[node->file_no],node->line_no);
kb_error(1261,errmsg,RECOVERABLE);
}
stacktop[0] = (REAL)((int)(stacktop[0])/(int)(stacktop[1]));
break;
case INTPOW:
/* cases n = 0,1,2 taken care of in parsing */
x = *stacktop;
k = node->op1.intpow < 0 ? -node->op1.intpow : node->op1.intpow;
for ( n = 1 ; n < k ; n++ )
*stacktop *= x;
if ( node->op1.intpow < 0 )
{ if ( *stacktop == 0.0 )
{ if ( valid_id(self_id) )
sprintf(errmsg,"Negative power (%d) of zero in %s, %s %s.\n",
node->op1.intpow,ex->name,
typenames[id_type(self_id)],ELNAME(self_id));
else sprintf(errmsg,"Negative power (%d) of zero in %s.\n",
node->op1.intpow,ex->name);
sprintf(errmsg+strlen(errmsg),"(source file %s, line %d)\n",
file_names[node->file_no],node->line_no);
kb_error(1262,errmsg,RECOVERABLE);
}
else
*stacktop = 1/(*stacktop);
}
break;
case POW:
stacktop--;
if ( (stacktop[0] < 0.0) && (floor(stacktop[1]) != stacktop[1]) )
{ if ( valid_id(self_id) )
sprintf(errmsg,
"Non-integer power of a negative number in %s, %s %s.\n",
ex->name, typenames[id_type(self_id)],ELNAME(self_id));
else sprintf(errmsg,"Non-integer power of a negative number in %s.\n",
ex->name);
sprintf(errmsg+strlen(errmsg),"(source file %s, line %d)\n",
file_names[node->file_no],node->line_no);
kb_error(2060,errmsg,RECOVERABLE);
}
if ( stacktop[0] == 0.0 )
{ if ( stacktop[1] >= 0.0 ) *stacktop = 0.0;
else *stacktop = 1e30;
}
else *stacktop = pow(stacktop[0],stacktop[1]);
/* Note: pow recognizes integer powers, so OK for neg x */
break;
case MAXIMUM_:
stacktop--;
*stacktop = (stacktop[0] > stacktop[1]) ? stacktop[0] : stacktop[1];
break;
case MINIMUM_:
stacktop--;
*stacktop = (stacktop[0] < stacktop[1]) ? stacktop[0] : stacktop[1];
break;
case WRAP_COMPOSE_:
stacktop--;
if ( sym_compose )
*stacktop = (REAL)(*sym_compose)((unsigned int)stacktop[0],(unsigned int)stacktop[1]);
break;
case WRAP_INVERSE_:
if ( sym_compose )
*stacktop = (REAL)(*sym_inverse)((unsigned int)stacktop[0]);
break;
case ATAN2_:
stacktop--;
*stacktop = atan2(stacktop[0],stacktop[1]);
break;
case SQR:
*stacktop *= *stacktop;
break;
case SQRT:
if ( *stacktop < 0.0 )
{ if ( *stacktop > -100*machine_eps ) *stacktop = 0.0;
else
{ if ( valid_id(self_id) )
sprintf(errmsg,"Square root of negative number in %s, %s %s.\n",
ex->name,typenames[id_type(self_id)],ELNAME(self_id));
else
sprintf(errmsg,"Square root of negative number in %s.\n",ex->name);
sprintf(errmsg+strlen(errmsg),"(source file %s, line %d)\n",
file_names[node->file_no],node->line_no);
kb_error(1263,errmsg,RECOVERABLE);
}
}
else *stacktop = sqrt(*stacktop);
break;
case CEIL_:
*stacktop = ceil(*stacktop);
break;
case FLOOR_:
*stacktop = floor(*stacktop);
break;
case ABS:
*stacktop = fabs(*stacktop);
break;
case SIN:
*stacktop = sin(*stacktop);
break;
case COS:
*stacktop = cos(*stacktop);
break;
case TAN:
*stacktop = tan(*stacktop);
break;
case EXP:
*stacktop = exp(*stacktop);
break;
case SINH:
*stacktop = (exp(*stacktop)-exp(-*stacktop))/2;
break;
case COSH:
*stacktop = (exp(*stacktop)+exp(-*stacktop))/2;
break;
case TANH:
y = exp(*stacktop);
*stacktop = (y*y-1)/(y*y+1) ;
break;
case ASINH:
*stacktop = log(*stacktop + sqrt(*stacktop*(*stacktop) + 1));
break;
case ACOSH:
if ( *stacktop < 1.0 )
{ if ( valid_id(self_id) )
sprintf(errmsg,"Acosh argument less than 1 in %s, %s %s.\n",
ex->name,typenames[id_type(self_id)],ELNAME(self_id));
else sprintf(errmsg,"Acosh argument less than 1 in %s.\n",ex->name);
sprintf(errmsg+strlen(errmsg),"(source file %s, line %d)\n",
file_names[node->file_no],node->line_no);
kb_error(2557,errmsg,RECOVERABLE);
}
*stacktop = 2*log(sqrt(*stacktop+1) + sqrt(*stacktop - 1)) - log(2.0);
break;
case ATANH:
if ( fabs(*stacktop) >= 1.0 )
{ if ( valid_id(self_id) )
sprintf(errmsg,
"Atanh argument magnitude not less than 1 in %s, %s %s.\n",
ex->name,typenames[id_type(self_id)],ELNAME(self_id));
else
sprintf(errmsg,"Atanh argument magnitude not less than 1 in %s.\n",
ex->name);
sprintf(errmsg+strlen(errmsg),"(source file %s, line %d)\n",
file_names[node->file_no],node->line_no);
kb_error(2559,errmsg, RECOVERABLE);
}
*stacktop = log(*stacktop+1)/2 - log(1-*stacktop)/2;
break;
case LOG:
if ( *stacktop <= 0.0 )
{ if ( valid_id(self_id) )
sprintf(errmsg,"Log of zero or negative number in %s, %s %s.\n",
ex->name,typenames[id_type(self_id)],ELNAME(self_id));
else sprintf(errmsg,"Log of zero or negative number in %s.\n",
ex->name);
sprintf(errmsg+strlen(errmsg),"(source file %s, line %d)\n",
file_names[node->file_no],node->line_no);
kb_error(1264,errmsg, RECOVERABLE );
}
*stacktop = log(*stacktop);
break;
case ASIN:
if ( *stacktop > 1.0 ) *stacktop = asin(1.0);
else if ( *stacktop < -1.0 ) *stacktop = asin(-1.0);
else *stacktop = asin(*stacktop);
break;
case ACOS:
if ( *stacktop > 1.0 ) *stacktop = 0.0;
else if ( *stacktop < -1.0 ) *stacktop = M_PI;
else *stacktop = acos(*stacktop);
break;
case ATAN:
*stacktop = atan(*stacktop);
break;
case ELLIPTICK:
*stacktop = ellipticK(*stacktop);
break;
case ELLIPTICE:
*stacktop = ellipticE(*stacktop);
break;
case INCOMPLETE_ELLIPTICF:
stacktop--;
*stacktop = incompleteEllipticF(stacktop[0],stacktop[1]);
break;
case INCOMPLETE_ELLIPTICE:
stacktop--;
*stacktop = incompleteEllipticE(stacktop[0],stacktop[1]);
break;
case CHS:
*stacktop = -*stacktop;
break;
case INV:
if ( *stacktop == 0.0 )
{ if ( valid_id(self_id) )
sprintf(errmsg,"Division by zero in %s, %s %s.\n",ex->name,
typenames[id_type(self_id)],ELNAME(self_id));
else sprintf(errmsg,"Division by zero in %s.\n",ex->name);
sprintf(errmsg+strlen(errmsg),"(source file %s, line %d)\n",
file_names[node->file_no],node->line_no);
kb_error(2560,errmsg,RECOVERABLE);
}
*stacktop = 1/(*stacktop);
break;
/* here are attributes for queries */
case COORD_:
if ( node->op1.localnum )
id = *(element_id*)get_localp(node->op1.localnum);
else id = q_id;
switch ( id_type(id) )
{ case VERTEX:
*++stacktop = get_coord(id)[node->op2.coordnum];
break;
case EDGE:
get_edge_side(id,vect);
*++stacktop = vect[node->op2.coordnum];
break;
case FACET:
get_facet_normal(id,vect);
*++stacktop = vect[node->op2.coordnum];
break;
}
break;
case INDEXED_COORD_:
{ int k = (int)*stacktop - 1; /* 1 based indexing */
if ( k < 0 || k >= SDIM )
{ sprintf(errmsg,
"Invalid index %d for x in %s; must be between 1 and %d, inclusive.\n",
k+1,ex->name,SDIM);
sprintf(errmsg+strlen(errmsg),"(source file %s, line %d)\n",
file_names[node->file_no],node->line_no);
kb_error(2061,errmsg,RECOVERABLE );
}
if ( node->op1.localnum )
id = *(element_id*)get_localp(node->op1.localnum);
else id = q_id;
switch( id_type(id) )
{ case VERTEX:
*stacktop = get_coord(id)[k];
break;
case EDGE:
get_edge_side(id,vect);
*stacktop = vect[k];
break;
case FACET:
get_facet_normal(id,vect);
*stacktop = vect[k];
break;
default:
sprintf(errmsg,"Can't have indexed x on %s, in %s.\n",
typenames[id_type(id)], ex->name);
sprintf(errmsg+strlen(errmsg),"(source file %s, line %d)\n",
file_names[node->file_no],node->line_no);
kb_error(2062,errmsg,RECOVERABLE);
}
}
break;
case PRINT_VERTEXNORMAL_:
{ MAT2D(normal,MAXCOORD,MAXCOORD);
REAL mag;
int i;
int normcount;
if ( node->op1.localnum )
id = *(element_id*)get_localp(node->op1.localnum);
else id = q_id;
normcount = new_calc_vertex_normal(id,normal);
project_vertex_normals(id,normal,normcount);
mag = sqrt(SDIM_dot(normal[0],normal[0]));
if ( mag == 0.0 )
{ mag = 1; memset(normal[0],0,SDIM*sizeof(REAL));}
sprintf(msg,"{");
for ( i = 0 ; i < SDIM ; i++ )
{ if ( i > 0 ) strcat(msg,",");
#ifdef LONGDOUBLE
sprintf(msg+strlen(msg),"%#*.*L",DWIDTH,DPREC,normal[0][i]/mag);
#else
sprintf(msg+strlen(msg),"%17.15g",normal[0][i]/mag);
#endif
}
strcat(msg,"}\n");
outstring(msg);
break;
}
case GET_VERTEXNORMAL_:
{ MAT2D(normal,MAXCOORD,MAXCOORD);
int k = (int)*stacktop - 1; /* 1 based indexing */
REAL mag;
int normcount;
if ( k < 0 || k >= SDIM )
{ sprintf(errmsg,
"Invalid index %d for vertexnormal in %s; must be between 1 and %d.\n",
k+1,ex->name,SDIM);
sprintf(errmsg+strlen(errmsg),"(source file %s, line %d)\n",
file_names[node->file_no],node->line_no);
kb_error(2063,errmsg,RECOVERABLE );
}
if ( node->op1.localnum )
id = *(element_id*)get_localp(node->op1.localnum);
else id = q_id;
normcount = new_calc_vertex_normal(id,normal);
project_vertex_normals(id,normal,normcount);
mag = sqrt(SDIM_dot(normal[0],normal[0]));
*stacktop = mag == 0.0 ? 0.0 : normal[0][k]/mag;
}
break;
case PARAM_:
if ( node->op1.localnum )
id = *(element_id*)get_localp(node->op1.localnum);
else id = q_id;
*++stacktop = get_param(id)[node->op2.coordnum];
break;
case GET_SQ_MEAN_CURV_:
if ( node->op1.localnum )
id = *(element_id*)get_localp(node->op1.localnum);
else id = q_id;
*++stacktop = vertex_sq_mean_curvature(id);
break;
case GET_FIXEDVOL_:
if ( node->op1.localnum )
id = *(element_id*)get_localp(node->op1.localnum);
else id = q_id;
*++stacktop = get_battr(id)&FIXEDVOL ? 1.0 : 0.0;
break;
case GET_MEANCURV_:
if ( node->op1.localnum )
id = *(element_id*)get_localp(node->op1.localnum);
else id = q_id;
*++stacktop = vertex_mean_curvature(id);
break;
case GET_LENGTH_:
if ( node->op1.localnum )
id = *(element_id*)get_localp(node->op1.localnum);
else id = q_id;
if ( web.representation != STRING ) calc_edge(id);
*++stacktop = get_edge_length(id);
break;
case GET_DIHEDRAL_:
if ( node->op1.localnum )
id = *(element_id*)get_localp(node->op1.localnum);
else id = q_id;
if ( id_type(id) == EDGE ) *++stacktop = dihedral(id);
else if ( id_type(id) == VERTEX ) *++stacktop = vertex_angle(id);
else *++stacktop = 0.0;
break;
case GET_ORIENTATION_:
if ( node->op1.localnum )
id = *(element_id*)get_localp(node->op1.localnum);
else id = q_id;
*++stacktop = (get_attr(id) & NEGBOUNDARY) ? -1.0 : 1.0;
break;
case VALENCE_:
case GET_VALENCE_:
if ( node->op1.localnum )
id = *(element_id*)get_localp(node->op1.localnum);
else id = q_id;
switch ( id_type(id) )
{ case VERTEX:
if ( web.representation == SIMPLEX )
*++stacktop = (REAL)get_vertex_fvalence(id);
else
*++stacktop = (REAL)get_vertex_evalence(id);
break;
case EDGE:
*++stacktop = (REAL)get_edge_valence(id);
break;
case FACET:
*++stacktop = (REAL)get_facet_valence(id);
break;
case BODY:
*++stacktop = (REAL)get_body_valence(id);
break;
}
break;
case GET_EDGE_:
if ( node->op1.localnum )
id = *(element_id*)get_localp(node->op1.localnum);
else id = q_id;
*++stacktop = (REAL)(ordinal(get_fe_edge(id))+1);
break;
case GET_FACET_:
if ( node->op1.localnum )
id = *(element_id*)get_localp(node->op1.localnum);
else id = q_id;
*++stacktop = (REAL)(ordinal(get_fe_facet(id))+1);
break;
case AREA_:
case GET_AREA_:
if ( node->op1.localnum )
id = *(element_id*)get_localp(node->op1.localnum);
else id = q_id;
*++stacktop = get_facet_area(id);
break;
case GET_MID_EDGE_:
if ( node->op1.localnum )
id = *(element_id*)get_localp(node->op1.localnum);
else id = q_id;
*++stacktop = get_vattr(id) & (Q_MIDEDGE|Q_MIDPOINT) ? 1.0 : 0.0;
break;
case GET_MID_FACET_:
if ( node->op1.localnum )
id = *(element_id*)get_localp(node->op1.localnum);
else id = q_id;
*++stacktop = get_vattr(id) & Q_MIDFACET ? 1.0 : 0.0;
break;
case GET_WRAP_:
if ( node->op1.localnum )
id = *(element_id*)get_localp(node->op1.localnum);
else id = q_id;
*++stacktop = web.symmetry_flag ? (REAL)get_edge_wrap(id) : 0;
break;
case GET_PRESSURE_:
if ( node->op1.localnum )
id = *(element_id*)get_localp(node->op1.localnum);
else id = q_id;
switch ( id_type(id) )
{
case BODY: *++stacktop = get_body_pressure(id); break;
default:
sprintf(errmsg,"Pressure only for bodies, in %s.\n",ex->name);
sprintf(errmsg+strlen(errmsg),"(source file %s, line %d)\n",
file_names[node->file_no],node->line_no);
kb_error(1267,errmsg,RECOVERABLE);
}
break;
case GET_USERATTR_:
if ( node->op1.localnum )
id = *(element_id*)get_localp(node->op1.localnum);
else id = q_id;
*++stacktop = user_attribute(id);
break;
case GET_QUANTITY_:
if ( node->op1.localnum )
id = *(element_id*)get_localp(node->op1.localnum);
else id = q_id;
if ( !valid_id(id) )
{ sprintf(errmsg,
"Quantity name '%s' needs attribute like .value (in %s)\n",
GEN_QUANT(node->op2.quant_id)->name,ex->name);
sprintf(errmsg+strlen(errmsg),"(source file %s, line %d)\n",
file_names[node->file_no],node->line_no);
kb_error(2064,errmsg, RECOVERABLE);
}
*++stacktop = quantity_attribute(id,node->op2.quant_id);
break;
case GET_INSTANCE_:
if ( node->op1.localnum )
id = *(element_id*)get_localp(node->op1.localnum);
else id = q_id;
if ( !valid_id(id) )
{ sprintf(errmsg,
"Instance name '%s' needs attribute like .value (in %s)\n",
METH_INSTANCE(node->op2.meth_id)->name,ex->name);
sprintf(errmsg+strlen(errmsg),"(source file %s, line %d)\n",
file_names[node->file_no],node->line_no);
kb_error(2065,errmsg, RECOVERABLE);
}
*++stacktop = instance_attribute(id,node->op2.meth_id);
break;
case GET_PHASE_:
if ( node->op1.localnum )
id = *(element_id*)get_localp(node->op1.localnum);
else id = q_id;
switch ( id_type(id) )
{
case FACET: *++stacktop = (REAL)get_f_phase(id); break;
case BODY: *++stacktop = (REAL)get_b_phase(id); break;
default:
sprintf(errmsg,"Phase of wrong type element in %s.\n",ex->name);
sprintf(errmsg+strlen(errmsg),"(source file %s, line %d)\n",
file_names[node->file_no],node->line_no);
kb_error(1268,errmsg,RECOVERABLE);
}
break;
case DENSITY_:
case GET_DENSITY_:
if ( node->op1.localnum )
id = *(element_id*)get_localp(node->op1.localnum);
else id = q_id;
switch ( id_type(id) )
{ case EDGE: *++stacktop = get_edge_density(id); break;
case FACET: *++stacktop = get_facet_density(id); break;
case BODY: *++stacktop = get_body_density(id); break;
default:
sprintf(errmsg,"Density of wrong type element in %s.\n",ex->name);
sprintf(errmsg+strlen(errmsg),"(source file %s, line %d)\n",
file_names[node->file_no],node->line_no);
kb_error(1269,errmsg,RECOVERABLE);
}
break;
case GET_STAR_:
if ( node->op1.localnum )
id = *(element_id*)get_localp(node->op1.localnum);
else id = q_id;
switch ( id_type(id) )
{ case VERTEX: *++stacktop = get_vertex_star(id); break;
case EDGE: *++stacktop = get_edge_star(id); break;
default: *++stacktop = 0.0; break;
}
break;
case VOLUME_:
case GET_VOLUME_:
{ int attr;
if ( node->op1.localnum )
id = *(element_id*)get_localp(node->op1.localnum);
else id = q_id;
attr = get_battr(id);
if ( attr & FIXEDVOL )
{ if (fixed_volume_timestamp < global_timestamp)
calc_content(Q_FIXED);
}
else
if ( (info_volume_timestamp < global_timestamp) )
calc_content(Q_INFO|Q_ENERGY);
*++stacktop = get_body_volume(id);
break;
}
case GET_VOLCONST_:
if ( node->op1.localnum )
id = *(element_id*)get_localp(node->op1.localnum);
else id = q_id;
*++stacktop = get_body_volconst(id);
break;
case GET_TARGET_:
if ( node->op1.localnum )
id = *(element_id*)get_localp(node->op1.localnum);
else id = q_id;
*++stacktop = get_body_fixvol(id);
break;
case ID_:
case GET_ID_:
case GET_OID_:
if ( node->op1.localnum )
id = *(element_id*)get_localp(node->op1.localnum);
else id = q_id;
if ( (node->type == GET_OID_) && inverted(id) )
*++stacktop = -(REAL)(ordinal(id)+1);
else *++stacktop = (REAL)(ordinal(id)+1);
break;
case ORIGINAL_:
case GET_ORIGINAL_: /* as user's element id number */
if ( node->op1.localnum )
id = *(element_id*)get_localp(node->op1.localnum);
else id = q_id;
*++stacktop = valid_id(id) ? (REAL)ordinal(get_original(id))+1 : 0;
break;
case GET_MPI_TASK_:
if ( node->op1.localnum )
id = *(element_id*)get_localp(node->op1.localnum);
else id = q_id;
*++stacktop = id_task(id);
break;
case GET_COLOR_:
if ( node->op1.localnum )
id = *(element_id*)get_localp(node->op1.localnum);
else id = q_id;
switch ( id_type(id) )
{ case EDGE: *++stacktop = (REAL)get_edge_color(id); break;
case FACET: *++stacktop = (REAL)get_facet_color(id); break;
default: *++stacktop = 0.0;
}
break;
case GET_FRONTCOLOR_:
if ( node->op1.localnum )
id = *(element_id*)get_localp(node->op1.localnum);
else id = q_id;
switch ( id_type(id) )
{ case FACET: *++stacktop = (REAL)get_facet_frontcolor(id); break;
default: *++stacktop = 0.0;
}
break;
case GET_BACKCOLOR_:
if ( node->op1.localnum )
id = *(element_id*)get_localp(node->op1.localnum);
else id = q_id;
switch ( id_type(id) )
{ case FACET: *++stacktop = (REAL)get_facet_backcolor(id); break;
default: *++stacktop = 0.0;
}
break;
case GET_FRONTBODY_:
if ( node->op1.localnum )
id = *(element_id*)get_localp(node->op1.localnum);
else id = q_id;
switch ( id_type(id) )
{ case EDGE:
fe = get_edge_fe(id);
if ( !valid_id(fe) ) {*++stacktop = 0.0; break;}
f_id = get_fe_facet(fe);
if ( inverted(f_id) ) f_id = get_fe_facet(get_next_facet(fe));
if ( inverted(f_id) ) { *++stacktop = 0.0; break;}
*++stacktop = (REAL)ordinal(get_facet_body(f_id))+1;
break;
case FACET:
*++stacktop = (REAL)ordinal(get_facet_body(id))+1;
break;
default: *++stacktop = 0.0;
}
break;
case GET_BACKBODY_:
if ( node->op1.localnum )
id = *(element_id*)get_localp(node->op1.localnum);
else id = q_id;
switch ( id_type(id) )
{ case FACET: *++stacktop =
(REAL)ordinal(get_facet_body(inverse_id(id)))+1;
break;
case EDGE:
fe = get_edge_fe(id);
if ( !valid_id(fe) ) {*++stacktop = 0.0; break;}
f_id = get_fe_facet(fe);
if ( !inverted(f_id) ) f_id = get_fe_facet(get_next_facet(fe));
if ( !inverted(f_id) ) { *++stacktop = 0.0; break;}
*++stacktop = (REAL)ordinal(get_facet_body(inverse_id(f_id)))+1;
break;
default: *++stacktop = 0.0;
}
break;
case TAG_:
case GET_TAG_:
if ( node->op1.localnum )
id = *(element_id*)get_localp(node->op1.localnum);
else id = q_id;
*++stacktop = (REAL)get_tag(id);
break;
case GET_BARE_:
if ( node->op1.localnum )
id = *(element_id*)get_localp(node->op1.localnum);
else id = q_id;
*++stacktop = (get_attr(id) & BARE_NAKED) ? 1.0 : 0.0;
break;
case GET_MIDV_:
if ( web.modeltype != QUADRATIC )
{ sprintf(errmsg,"Cannot do MIDV except in QUADRATIC model (in %s).\n",
ex->name);
sprintf(errmsg+strlen(errmsg),"(source file %s, line %d)\n",
file_names[node->file_no],node->line_no);
kb_error(2066,errmsg,RECOVERABLE);
}
if ( node->op1.localnum )
id = *(element_id*)get_localp(node->op1.localnum);
else id = q_id;
*++stacktop = ordinal(get_edge_midv(id)) + 1.0;
break;
case FIXED_:
case GET_FIXED_:
if ( node->op1.localnum )
id = *(element_id*)get_localp(node->op1.localnum);
else id = q_id;
if ( id_type(id) == BODY )
*++stacktop = get_battr(id)&FIXEDVOL ? 1.0 : 0.0;
else *++stacktop = (get_attr(id) & FIXED) ? 1.0 : 0.0;
break;
case GET_NO_DISPLAY_:
if ( node->op1.localnum )
id = *(element_id*)get_localp(node->op1.localnum);
else id = q_id;
*++stacktop = (get_attr(id) & NODISPLAY) ? 1.0 : 0.0;
break;
case GET_NONCONTENT_:
if ( node->op1.localnum )
id = *(element_id*)get_localp(node->op1.localnum);
else id = q_id;
*++stacktop = (get_attr(id) & NONCONTENT) ? 1.0 : 0.0;
break;
case GET_HIT_PARTNER_:
if ( node->op1.localnum )
id = *(element_id*)get_localp(node->op1.localnum);
else id = q_id;
*++stacktop = (get_attr(id) & HIT_PARTNER) ? 1.0 : 0.0;
break;
case GET_NO_REFINE_:
if ( node->op1.localnum )
id = *(element_id*)get_localp(node->op1.localnum);
else id = q_id;
*++stacktop = (get_attr(id) & NO_REFINE) ? 1.0 : 0.0;
break;
case GET_TRIPLE_PT_:
if ( node->op1.localnum )
id = *(element_id*)get_localp(node->op1.localnum);
else id = q_id;
*++stacktop = (get_attr(id) & TRIPLE_PT) ? 1.0 : 0.0;
break;
case GET_TETRA_PT_:
if ( node->op1.localnum )
id = *(element_id*)get_localp(node->op1.localnum);
else id = q_id;
*++stacktop = (get_attr(id) & TETRA_PT) ? 1.0 : 0.0;
break;
case GET_AXIAL_POINT_:
if ( node->op1.localnum )
id = *(element_id*)get_localp(node->op1.localnum);
else id = q_id;
*++stacktop = (get_attr(id) & AXIAL_POINT) ? 1.0 : 0.0;
break;
case GET_SHOW_:
if ( node->op1.localnum )
id = *(element_id*)get_localp(node->op1.localnum);
else id = q_id;
if ( id_type(id) == EDGE )
{ int eattr = get_eattr(id);
int showflag = 0;
facetedge_id fe_id = get_edge_fe(id);
if ( eattr & BOUNDARY ) showflag = 1;
if ( equal_id(get_next_facet(fe_id),fe_id) ) /* valence 1 */
showflag = 1;
else if ( !equal_id(get_next_facet(fe_id),get_prev_facet(fe_id)) )
showflag = 1;
if ( eattr & HIT_WALL ) showflag = 1;
if ( eattr & FIXED ) showflag = 1;
if ( show_expr[EDGE] && show_expr[EDGE]->start )
{
PROF_EVAL_END(ex);
showflag = eval(show_expr[EDGE],NULL,id,NULL) ? 1 : 0;
PROF_EVAL_START(ex);
}
if ( get_edge_color(id) == CLEAR ) showflag = 0;
*++stacktop = showflag;
}
else if ( id_type(id) == FACET )
{ int fattr = get_fattr(id);
int showflag = 1;
if ( (fattr & (BOUNDARY|CONSTRAINT)) && !bdry_showflag )
showflag = 0;
if ( fattr & NODISPLAY )
showflag = 0;
if ( no_wall_flag )
{ /* skip facets with all three vertices on walls */
fe = get_facet_fe(id);
if ( get_vattr(get_fe_headv(fe)) & (HIT_WALL|CONSTRAINT) )
if ( get_vattr(get_fe_tailv(fe)) & (HIT_WALL|CONSTRAINT) )
{ fe = get_next_edge(fe);
if ( get_vattr(get_fe_headv(fe)) & (HIT_WALL|CONSTRAINT) )
showflag = 0;
}
}
if ( show_expr[FACET] && show_expr[FACET]->start )
{
PROF_EVAL_END(ex);
if ( !eval(show_expr[FACET],NULL,id,NULL) )
showflag = 0;
PROF_EVAL_START(ex);
}
*++stacktop = showflag;
}
else
{ sprintf(errmsg,
"\"show\" attribute applied to wrong type of element in %s.\n",
ex->name);
sprintf(errmsg+strlen(errmsg),"(source file %s, line %d)\n",
file_names[node->file_no],node->line_no);
kb_error(2067,errmsg,RECOVERABLE);
}
break;
case ATTR_FUNCTION_:
node += node->op1.skipsize - 1;
break;
case ATTR_FUNCTION_END_:
{ struct extra *ext = EXTRAS(node->op2.eltype) + node->op1.extranum;
ext->flags |= FUNCTION_ATTR;
tree_copy(&ext->code,node + node->right);
break;
}
case GET_EXTRA_ATTR_:
{ struct extra *ext;
int spot;
n = node->op3.extranum; /* attribute number */
if ( node->op1.localnum )
id = *(element_id*)get_localp(node->op1.localnum);
else id = q_id;
ext = EXTRAS(node->op2.eltype) + n;
/* get index */
spot = 0;
for ( k = 0 ; k < ext->array_spec.dim ; k++ )
{ int j = (int)(stacktop[-ext->array_spec.dim+k+1]);
spot *= ext->array_spec.sizes[k];
if ( (j < 1) || (j > ext->array_spec.sizes[k]) )
{ sprintf(errmsg,
"Attribute %s index %d is %d; maximum is %d (in %s).\n",
ext->name,k+1,j,ext->array_spec.sizes[k],ex->name);
sprintf(errmsg+strlen(errmsg),"(source file %s, line %d)\n",
file_names[node->file_no],node->line_no);
kb_error(1270,errmsg,RECOVERABLE);
}
spot += (int)(stacktop[-ext->array_spec.dim+k+1]) - 1;
}
stacktop -= ext->array_spec.dim;
if ( id_type(id) != node->op2.eltype )
{ if ( (id_type(id)==EDGE) && (node->op2.eltype==VERTEX) && params )
{ ext = EXTRAS(VERTEX) + n;
*++stacktop = interp_edge_attribute(id,ext,spot,(int)params[2*SDIM]);
break;
}
else
if ( (id_type(id)==FACET) && (node->op2.eltype==VERTEX) && params )
{ ext = EXTRAS(VERTEX) + n;
*++stacktop = interp_facet_attribute(id,ext,spot,(int)params[2*SDIM]);
break;
}
else
{ sprintf(errmsg,
"Attribute %s is %s attribute, not %s attribute (in %s).\n",
EXTRAS(node->op2.eltype)[n].name,
typenames[node->op2.eltype], typenames[id_type(id)],ex->name);
sprintf(errmsg+strlen(errmsg),"(source file %s, line %d)\n",
file_names[node->file_no],node->line_no);
kb_error(2068,errmsg,RECOVERABLE);
}
}
if ( ext->code.start )
{ int oldflag = autorecalc_flag;
autorecalc_flag = 0;
PROF_EVAL_END(ex);
eval(&ext->code,NULL,id,NULL); /* side-effect fills in values */
PROF_EVAL_START(ex);
autorecalc_flag = oldflag;
}
switch ( ext->type )
{ case REAL_TYPE: *++stacktop = ((REAL*)get_extra(id,n))[spot];
break;
case INTEGER_TYPE:
case CONSTRAINT_TYPE:
case BOUNDARY_TYPE:
case QUANTITY_TYPE:
case INSTANCE_TYPE:
case PROCEDURE_TYPE:
*++stacktop = (REAL)((int*)get_extra(id,n))[spot];
break;
case UINT_TYPE:
*++stacktop = (REAL)((unsigned int*)get_extra(id,n))[spot];
break;
case ULONG_TYPE:
*++stacktop = (REAL)((unsigned long*)get_extra(id,n))[spot];
break;
case LONG_TYPE:
*++stacktop = (REAL)((long*)get_extra(id,n))[spot];
break;
case UCHAR_TYPE:
*++stacktop = (REAL)((unsigned char*)get_extra(id,n))[spot];
break;
case CHAR_TYPE:
*++stacktop = (REAL)((char*)get_extra(id,n))[spot];
break;
case SHORT_TYPE:
*++stacktop = (REAL)((short int*)get_extra(id,n))[spot];
break;
case USHORT_TYPE:
*++stacktop = (REAL)((unsigned short int*)get_extra(id,n))[spot];
break;
case ELEMENTID_TYPE:
case VERTEX_TYPE:
case EDGE_TYPE:
case FACET_TYPE:
case BODY_TYPE:
case FACETEDGE_TYPE:
*(element_id*)(++stacktop) =
((element_id*)get_extra(id,n))[spot];
break;
case PTR_TYPE:
*((char**)++stacktop) = (((char**)get_extra(id,n))[spot]);
break;
}
}
break;
case ON_CONSTRAINT_:
case ON_CONSTRAINT_NAME:
{ int testcon = (node->type == ON_CONSTRAINT_) ? (int)*(stacktop--)
: node->op3.connum;
if ( node->op1.localnum )
id = *(element_id*)get_localp(node->op1.localnum);
else id = q_id;
switch(id_type(id))
{ case VERTEX: *++stacktop = (REAL)v_on_constraint(id,testcon); break;
case EDGE : *++stacktop = (REAL)e_on_constraint(id,testcon); break;
case FACET : *++stacktop = (REAL)f_on_constraint(id,testcon); break;
default:
sprintf(errmsg,
"Can't do constraints on this type element (in %s).\n",
ex->name);
sprintf(errmsg+strlen(errmsg),"(source file %s, line %d)\n",
file_names[node->file_no],node->line_no);
kb_error(1272,errmsg,RECOVERABLE);
}
}
break;
case HIT_CONSTRAINT_:
case HIT_CONSTRAINT_NAME:
{ int testcon = (node->type == HIT_CONSTRAINT_) ? (int)*(stacktop--)
: node->op3.connum;
if ( node->op1.localnum )
id = *(element_id*)get_localp(node->op1.localnum);
else id = q_id;
switch(id_type(id))
{ case VERTEX: *++stacktop = (REAL)get_v_constraint_status(id,testcon);
break;
default:
sprintf(errmsg,
"Can do hit_constraints only on vertices (in %s).\n",ex->name);
sprintf(errmsg+strlen(errmsg),"(source file %s, line %d)\n",
file_names[node->file_no],node->line_no);
kb_error(1273,errmsg,RECOVERABLE);
}
}
break;
case ON_BOUNDARY_:
case ON_BOUNDARY_NAME:
{ struct boundary *b=NULL;
int testb = (node->type == ON_BOUNDARY_) ? (int)*(stacktop--)
: node->op3.bdrynum;
if ( node->op1.localnum )
id = *(element_id*)get_localp(node->op1.localnum);
else id = q_id;
switch(id_type(id))
{ case VERTEX: b = get_boundary(id); break;
case EDGE : b = get_edge_boundary(id); break;
case FACET : b = get_facet_boundary(id); break;
default:
sprintf(errmsg,
"Can't do boundary on a %s (in %s).\n",
typenames[id_type(id)],ex->name);
sprintf(errmsg+strlen(errmsg),"(source file %s, line %d)\n",
file_names[node->file_no],node->line_no);
kb_error(1274,errmsg,RECOVERABLE);
}
*++stacktop = (b == web.boundaries+testb) ? 1.0 : 0.0;
}
break;
case ON_METHOD_INSTANCE_:
{ struct element *eptr;
int *mptr;
if ( node->op1.localnum )
id = *(element_id*)get_localp(node->op1.localnum);
else id = q_id;
eptr = elptr(id);
mptr = (int*)((char*)eptr+get_meth_offset(id_type(id)));
for ( i = 0 ; i < eptr->method_count ; i++ )
if ( abs(node->op2.meth_id) == abs(mptr[i]) )
{ *++stacktop = 1.0;
break;
}
if ( i == eptr->method_count )
*++stacktop = 0.0;
break;
}
case ON_QUANTITY_:
{ struct element *eptr;
int *mptr;
struct method_instance *mi;
if ( node->op1.localnum )
id = *(element_id*)get_localp(node->op1.localnum);
else id = q_id;
eptr = elptr(id);
mptr = (int*)((char*)eptr+get_meth_offset(id_type(id)));
for ( i = 0 ; i < eptr->method_count ; i++ )
{ mi = METH_INSTANCE(abs(mptr[i]));
if ( mi->quant == node->op2.quant_id )
{ *++stacktop = 1.0;
break;
}
}
if ( i == eptr->method_count )
*++stacktop = 0.0;
break;
}
case SELF_ELEMENT_:
if ( !valid_id(self_id) )
{ sprintf(errmsg,"No element for SELF to refer to in %s.\n",ex->name);
sprintf(errmsg+strlen(errmsg),"(source file %s, line %d)\n",
file_names[node->file_no],node->line_no);
kb_error(2069,errmsg,RECOVERABLE);
}
*(element_id*)get_localp(node->op2.localnum) = self_id;
break;
case SYMBOL_ELEMENT_:
break;
case SINGLE_ELEMENT_EXPR_:
*(element_id*)(++stacktop) =
*(element_id*)get_localp(node[node->left].op2.localnum);
break;
case ELEMENT_IDENT_:
*(element_id*)get_localp(node->op2.localnum)
= globals(node->op3.name_id)->value.id;
break;
case INDEXED_SUBTYPE_: /* like ee.vertex[1] */
{ element_id next_id = NULLID;
int ord = (int)*(stacktop--) - 1; /* which one */
element_id parent = node[node->left].op2.localnum ?
*(element_id*)get_localp(node[node->left].op2.localnum) : q_id;
int ptype = id_type(parent);
element_id first; /* sentinel for looping */
if ( ord < 0 )
{ sprintf(errmsg,"Element index must be positive in %s.\n",ex->name);
sprintf(errmsg+strlen(errmsg),"(source file %s, line %d)\n",
file_names[node->file_no],node->line_no);
kb_error(1275,errmsg,RECOVERABLE);
}
id=NULLID;
switch ( ptype )
{
case VERTEX:
switch ( node->op1.eltype )/* subtype */
{
case EDGE: /* indexed edge of vertex */
id = first = get_vertex_edge(parent);
if ( !valid_element(id) )
{ sprintf(errmsg,"Vertex %s has no edges.\n",ELNAME(parent));
sprintf(errmsg+strlen(errmsg),"(source file %s, line %d)\n",
file_names[node->file_no],node->line_no);
kb_error(1276,errmsg,RECOVERABLE);
}
for ( n = 1 ; n <= ord ; n++ )
{ id = get_next_tail_edge(id);
if ( equal_id(id,first) )
{ sprintf(errmsg,"Edge index %d exceeds valence of vertex %s.\n",
ord+1,ELNAME(id));
sprintf(errmsg+strlen(errmsg),"(source file %s, line %d)\n",
file_names[node->file_no],node->line_no);
kb_error(1277,errmsg,RECOVERABLE);
}
}
next_id = id;
break;
case FACET: /* indexed facet of vertex */
id = first = get_vertex_first_facet(parent);
if ( !valid_element(id) )
{ sprintf(errmsg,"Vertex %s has no facets.\n",ELNAME(parent));
sprintf(errmsg+strlen(errmsg),"(source file %s, line %d)\n",
file_names[node->file_no],node->line_no);
kb_error(1278,errmsg,RECOVERABLE);
}
for ( n = 1 ; n <= ord ; n++ )
{ id = get_next_vertex_facet(parent,id);
if ( equal_id(id,first) )
{ sprintf(errmsg,
"Facet index %d exceeds facet valence of vertex %s.\n",
ord+1,ELNAME(parent));
sprintf(errmsg+strlen(errmsg),"(source file %s, line %d)\n",
file_names[node->file_no],node->line_no);
kb_error(1279,errmsg,RECOVERABLE);
}
}
if ( id_type(id) == FACETEDGE )
id = get_fe_facet(id);
next_id = positive_id(id);
break;
}
break;
case EDGE:
switch ( node->op1.eltype /* subtype */ )
{ case VERTEX:
if ( ord >= web.skel[EDGE].ctrlpts )
{ sprintf(errmsg,
"Index, %d, exceeds the number of vertices on an edge, %d.\n",
ord+1,web.skel[EDGE].ctrlpts);
sprintf(errmsg+strlen(errmsg),"(source file %s, line %d)\n",
file_names[node->file_no],node->line_no);
kb_error(1280,errmsg, RECOVERABLE);
}
if ( web.modeltype == LAGRANGE )
{ next_id = get_edge_vertices(parent)
[inverted(parent) ? web.skel[EDGE].ctrlpts-ord-1 : ord];
}
else
switch ( ord )
{ case 0: next_id = get_edge_tailv(parent); break;
case 1: next_id = get_edge_headv(parent); break;
case 2: next_id = get_edge_midv(parent); break;
}
break;
case FACET:
id = first = get_edge_fe(parent);
if ( !valid_element(id) )
{ sprintf(errmsg,"Edge %s has no facets.\n",ELNAME(parent));
sprintf(errmsg+strlen(errmsg),"(source file %s, line %d)\n",
file_names[node->file_no],node->line_no);
kb_error(1176,errmsg,RECOVERABLE);
}
for ( n = 1 ; n <= ord ; n++ )
{ id = get_next_facet(id);
if ( equal_id(id,first) )
{ sprintf(errmsg,
"Facet index, %d, exceeds number of facets on edge %s.\n",
ord+1,ELNAME(parent));
sprintf(errmsg+strlen(errmsg),"(source file %s, line %d)\n",
file_names[node->file_no],node->line_no);
kb_error(1186,errmsg,RECOVERABLE);
}
}
next_id = get_fe_facet(id);
break;
case FACETEDGE:
id = first = get_edge_fe(parent);
if ( !valid_element(id) )
{ sprintf(errmsg,"Edge %s has no facets.\n",ELNAME(parent));
sprintf(errmsg+strlen(errmsg),"(source file %s, line %d)\n",
file_names[node->file_no],node->line_no);
kb_error(1281,errmsg,RECOVERABLE);
}
for ( n = 1 ; n <= ord ; n++ )
{ id = get_next_facet(id);
if ( equal_id(id,first) )
{ sprintf(errmsg,
"Facetedge index, %d, exceeds valence on edge %s.\n",
ord+1,ELNAME(parent));
sprintf(errmsg+strlen(errmsg),"(source file %s, line %d)\n",
file_names[node->file_no],node->line_no);
kb_error(1282,errmsg,RECOVERABLE);
}
}
next_id = id;
break;
}
break;
case FACET:
switch ( node->op1.eltype /* subtype */ )
{ case VERTEX:
if ( (web.representation == SIMPLEX) ||
(web.modeltype == LAGRANGE) )
{ if ( ord >= web.skel[FACET].ctrlpts )
{ sprintf(errmsg,
"Vertex index, %d, exceeds number of vertices on facet %s.\n",
ord+1,ELNAME(parent));
sprintf(errmsg+strlen(errmsg),"(source file %s, line %d)\n",
file_names[node->file_no],node->line_no);
kb_error(3503,errmsg,RECOVERABLE);
}
next_id = get_facet_vertices(parent)[ord];
break;
}
if ( (web.modeltype == QUADRATIC) &&
(web.representation == SOAPFILM) )
{ if ( ord >= web.skel[FACET].ctrlpts )
{ sprintf(errmsg,
"Vertex index, %d, exceeds number of vertices on facet %s.\n",
ord+1,ELNAME(parent));
sprintf(errmsg+strlen(errmsg),"(source file %s, line %d)\n",
file_names[node->file_no],node->line_no);
kb_error(3504,errmsg,RECOVERABLE);
}
fe = get_facet_fe(parent);
if ( ord < 3 )
{ for ( i = 0 ; i < ord ; i++ )
fe = get_next_edge(fe);
next_id = get_fe_tailv(fe);
}
else
{ for ( i = 3 ; i < ord ; i++ )
fe = get_next_edge(fe);
next_id = get_fe_midv(fe);
}
break;
}
/* now string */
id = first = get_facet_fe(parent);
if ( !valid_element(id) )
{ sprintf(errmsg,"Facet has no edges.\n");
sprintf(errmsg+strlen(errmsg),"(source file %s, line %d)\n",
file_names[node->file_no],node->line_no);
kb_error(1283,errmsg,RECOVERABLE);
}
if ( inverted(parent) )
{ facetedge_id nextfe=id,startfe=id;
/* go back round to find start */
do
{ id = nextfe;
nextfe = get_prev_edge(id);
} while ( valid_id(nextfe) && !equal_id(nextfe,startfe) );
first = id;
}
for ( n = 1 ; n <= ord ; n++ )
{ edge_id next_edge = get_next_edge(id);
if ( !valid_id(next_edge) && n == ord )
{ next_id = get_fe_headv(id);
id = NULLID;
break;
}
id = next_edge;
if ( !valid_id(id) || equal_id(id,first) )
{ sprintf(errmsg,
"Vertex index, %d, exceeds number of vertices on facet %s.\n",
ord+1,ELNAME(parent));
sprintf(errmsg+strlen(errmsg),"(source file %s, line %d)\n",
file_names[node->file_no],node->line_no);
kb_error(1284,errmsg,RECOVERABLE);
}
}
if ( valid_id(id) )
next_id = get_fe_tailv(id);
break;
case EDGE:
id = first = get_facet_fe(parent);
if ( !valid_element(id) )
{ sprintf(errmsg,"Facet has no edges.\n");
sprintf(errmsg+strlen(errmsg),"(source file %s, line %d)\n",
file_names[node->file_no],node->line_no);
kb_error(1285,errmsg,RECOVERABLE);
}
if ( inverted(parent) )
{ facetedge_id nextfe=id,startfe=id;
/* go back round to find start */
do
{ id = nextfe;
nextfe = get_prev_edge(id);
} while ( valid_id(nextfe) && !equal_id(nextfe,startfe) );
first = id;
}
for ( n = 1 ; n <= ord ; n++ )
{ id = get_next_edge(id);
if ( !valid_id(id) || equal_id(id,first) )
{ sprintf(errmsg,
"Edge index, %d, exceeds number of vertices on facet %s.\n",
ord+1,ELNAME(parent));
sprintf(errmsg+strlen(errmsg),"(source file %s, line %d)\n",
file_names[node->file_no],node->line_no);
kb_error(1286,errmsg,RECOVERABLE);
}
}
next_id = get_fe_edge(id);
break;
case BODY:
switch ( ord )
{ case 0: next_id = get_facet_body(parent); break;
case 1: next_id = get_facet_body(inverse_id(parent));
break;
default:
sprintf(errmsg,
"Illegal facet body index %d; must be 1 or 2.\n",ord+1);
sprintf(errmsg+strlen(errmsg),"(source file %s, line %d)\n",
file_names[node->file_no],node->line_no);
kb_error(1287,errmsg, RECOVERABLE);
break;
}
if ( !valid_id(next_id) )
{ sprintf(errmsg,"Facet %d does not have body of index %d.\n",
oid(parent),ord+1);
sprintf(errmsg+strlen(errmsg),"(source file %s, line %d)\n",
file_names[node->file_no],node->line_no);
kb_error(2070,errmsg,RECOVERABLE);
}
break;
}
break;
case BODY:
switch ( node->op1.eltype /* subtype */ )
{ case FACET:
/*
if ( bfacet_timestamp < top_timestamp ) make_bfacet_lists();
*/
id = first = get_body_facet(parent);
for ( n = 1 ; n <= ord ; n++ )
{
id = get_next_body_facet(id);
if ( equal_id(id,first) )
{ id = NULLID;
break;
}
}
if ( !valid_id(id) )
{ sprintf(errmsg,
"Facet index, %d, exceeds number of facets on body %s.\n",
ord+1, ELNAME(parent));
sprintf(errmsg+strlen(errmsg),"(source file %s, line %d)\n",
file_names[node->file_no],node->line_no);
kb_error(1288,errmsg,RECOVERABLE);
}
next_id = id;
break;
}
break;
case FACETEDGE:
switch ( node->op1.eltype /* subtype */ )
{ case EDGE: next_id = get_fe_edge(parent); break;
case FACET: next_id = get_fe_facet(parent); break;
}
break;
}
*(element_id*)get_localp(node->op2.localnum) = next_id;
} break; /* end INDEXED_SUBTYPE */
case INDEXED_ELEMENT_:
{ element_id partid = *(element_id*)(stacktop--);
element_id id;
id = get_full_id(node->op1.eltype,partid);
if ( !valid_id(id) )
{ sprintf(errmsg,"%s index %d is not valid.\n",
typenames[node->op1.eltype],
valid_id(partid) ? (int)(partid & OFFSETMASK)+1 : 0);
sprintf(errmsg+strlen(errmsg),"(source file %s, line %d)\n",
file_names[node->file_no],node->line_no);
kb_error(1200,errmsg,RECOVERABLE);
}
*(element_id *)get_localp(node->op2.localnum) = id;
break;
}
case QUALIFIED_ATTRIBUTE:
break; /* just a no-op in execution */
/****************************/
/* aggregate initialization */
/****************************/
case SET_INIT_:
web.where_count = 0;
/* break and continue jumps */
*(size_t*)(localstack + node->stackpos) = stacktop - localstack + 3;
#ifdef MPI_EVOLVER
if ( this_task == MASTER_TASK )
{ mpi_subtask_command_flag = 1;
mpi_aggregate(node,ex->locals->count);
}
#endif
break;
case AGGREGATE_INIT_:
aggregate_depth++;
web.where_count = 0;
/* break and continue jumps */
*(size_t*)(localstack + node->stackpos) = stacktop - localstack + 3;
switch ( node->op1.aggrtype )
{ case FOREACH_:
case SET_ATTRIBUTE_LOOP_:
break;
case MAX_:
*++stacktop = -MAXDOUBLE; /* max of empty set */
break;
case MIN_:
*++stacktop = MAXDOUBLE; /* min of empty set */
break;
case SUM_:
*++stacktop = 0.0; /* sum */
break;
case AVG_:
*++stacktop = 0.0; /* count */
*++stacktop = 0.0; /* sum */
break;
case COUNT_:
*++stacktop = 0.0; /* count */
break;
case HISTOGRAM_:
case LOGHISTOGRAM_:
*++stacktop = 0.0; /* first phase counter */
*++stacktop = MAXDOUBLE; /* min */
*++stacktop = -MAXDOUBLE; /* max */
for ( n = 0 ; n < HISTBINS+1 ; n++ )
*++stacktop = 0.0;
histo_max = web.skel[node->op2.eltype].count + 5;
histo_data = (REAL*)temp_calloc(histo_max,sizeof(REAL));
histo_count = 0;
break;
case LIST_: /* print column headers */
#ifdef MPI_EVOLVER
if ( (this_task == MASTER_TASK) || !mpi_subtask_command_flag )
#endif
switch ( node->op2.eltype )
{ case VERTEX:
if ( SDIM == 2 )
outstring("// Id X Y\n");
else
outstring("// Id X Y Z\n");
break;
case EDGE:
outstring("// Id endpoints\n");
break;
case FACET:
if ( web.representation == SIMPLEX )
outstring("// Id vertices\n");
else outstring("// Id edges\n");
break;
case BODY:
outstring("// Id facets\n");
break;
case FACETEDGE:
outstring("// id edge facet prevedge nextedge prevfacet nextfacet\n");
break;
}
break;
case REFINE_:
#ifdef MPI_EVOLVER
if ( (this_task != MASTER_TASK) && mpi_subtask_command_flag
&& node->op2.eltype == EDGE )
mpi_edge_refine_init();
#endif
break;
case DISSOLVE_:
break;
case DELETE_:
#ifdef MPI_EVOLVER
if ( this_task == MASTER_TASK )
mpi_set_corona(THIN_CORONA);
if ( (this_task != MASTER_TASK) && mpi_subtask_command_flag )
mpi_delete_init();
#endif
break;
case FIX_:
break;
case UNFIX_:
break;
case REVERSE_ORIENTATION_: break;
case EDGESWAP_: break;
case T1_EDGESWAP_: break;
case EQUIANGULATE_: break;
case POP_: case POP_TRI_TO_EDGE_:
case POP_EDGE_TO_TRI_: case POP_QUAD_TO_QUAD_:
break;
case VERTEX_AVERAGE_: break;
case RAW_VERTEX_AVERAGE_: break;
case RAWEST_VERTEX_AVERAGE_: break;
default:
sprintf(errmsg,"Internal error: Bad aggregate type %d.\n",
node->op1.aggrtype);
sprintf(errmsg+strlen(errmsg),"(source file %s, line %d)\n",
file_names[node->file_no],node->line_no);
kb_error(1290,errmsg, RECOVERABLE);
break;
}
#ifdef MPI_EVOLVER
if ( this_task == MASTER_TASK )
{ mpi_subtask_command_flag = 1;
mpi_aggregate(node,ex->locals->count);
}
#endif
break;
/* end case AGGREGATE_INIT */
/************************/
/* next element in loop */
/************************/
case SINGLE_ELEMENT_:
q_id = *(element_id*)get_localp(node[node->left].op2.localnum);
if ( stacktop[-1] > 0.0 ) /* done */
node += node->op1.skipsize;
else stacktop[-1] = 1.0;
break;
case NEXT_VERTEX_: /* all vertices */
{
vertex_id *vp;
vp = (element_id *)(stacktop - 0);
if ( !valid_id(*vp) || breakflag )
{ /* done */
node += node->op1.skipsize - 1;
break;
}
q_id = *vp;
*(element_id*)get_localp(node->op2.localnum) = q_id;
/* check sentinel; set for next time around */
if ( equal_id(*vp,*(vertex_id*)(stacktop-1)) ) *vp = NULLID;
else *vp = vptr(*vp)->forechain;
if ( !valid_element(q_id) ) node--; /* skip body of loop */
#ifdef MPI_EVOLVER
if ( mpi_subtask_command_flag && (id_task(q_id) != this_task) )
node--; /* don't count foreign vertices in global aggregate */
#endif
}
break;
case NEXT_EDGE_VERTEX_: /* edge vertices */
{
int *numptr;
vertex_id *vp;
numptr = (int *)(stacktop - 1);
if ( *numptr== web.skel[EDGE].ctrlpts )
{ /* done */
node += node->op1.skipsize - 1;
break;
}
vp = *(element_id **)(stacktop - 0);
q_id = vp[*numptr];
*(element_id*)get_localp(node->op2.localnum) = q_id;
(*numptr)++;
if ( !valid_element(q_id) ) node--; /* skip body of loop */
#ifdef MPI_EVOLVER
if ( mpi_subtask_command_flag && (id_task(q_id) != this_task) )
node--; /* don't count foreign elements in global aggregate */
#endif
break;
}
case NEXT_FACET_VERTEX_: /* facet vertices */
{
facetedge_id *fe_ptr;
facet_id *f_ptr;
if ( (web.representation == SIMPLEX) ||
(web.modeltype==LAGRANGE) )
{ int *numptr = (int *)(stacktop - 1);
if ( *numptr > web.skel[FACET].ctrlpts )
{ node += node->op1.skipsize - 1;
break;
}
f_ptr = (facet_id *)(stacktop);
q_id = get_facet_vertices(*f_ptr)[*numptr];
(*numptr)++;
}
else if ( (web.modeltype == QUADRATIC)
&& (web.representation == SOAPFILM) )
{ int *numptr = (int *)(stacktop - 1);
if ( *numptr >= web.skel[FACET].ctrlpts ) /* see if done */
{ node += node->op1.skipsize - 1;
break;
}
f_id = *(facet_id *)(stacktop);
fe = get_facet_fe(f_id);
if ( *numptr < 3 )
{ for ( i = 0 ; i < *numptr ; i++ )
fe = get_next_edge(fe);
q_id = get_fe_tailv(fe);
}
else
{ for ( i = 3 ; i < *numptr ; i++ )
fe = get_next_edge(fe);
q_id = get_fe_midv(fe);
}
(*numptr)++;
}
else
{ fe_ptr = (element_id *)(stacktop - 0);
if ( !valid_id(*fe_ptr) ) /* see if done */
{ node += node->op1.skipsize - 1;
break;
}
if ( id_type(*fe_ptr) == VERTEX )
{ /* last vertex in string unclosed facet */
q_id = *fe_ptr; *fe_ptr = NULLID;
}
else
{ edge_id e_id = get_fe_edge(*fe_ptr);
q_id = get_edge_tailv(e_id);
*fe_ptr = get_next_edge(*fe_ptr);
if ( !valid_id(*fe_ptr) )
*fe_ptr = get_edge_headv(e_id); /* end of string facet */
else if ( !valid_element(*fe_ptr)
|| equal_id(*fe_ptr,*(element_id *)(stacktop-1)))
*fe_ptr = NULLID; /* last one */
}
}
*(element_id*)get_localp(node->op2.localnum) = q_id;
if ( !valid_element(q_id) ) node--; /* skip body of loop */
#ifdef MPI_EVOLVER
if ( mpi_subtask_command_flag && (id_task(q_id) != this_task) )
node--; /* don't count foreign elements in global aggregate */
#endif
break;
}
case NEXT_BODY_VERTEX_: /* body vertices */
break;
case NEXT_EDGE_: /* all edges */
{
edge_id *ep;
ep = (element_id *)(stacktop - 0);
if ( !valid_id(*ep) || breakflag )
{ /* done */
node += node->op1.skipsize - 1;
break;
}
q_id = *ep;
*(element_id*)get_localp(node->op2.localnum) = q_id;
/* check sentinel; set for next time around */
if ( equal_id(*ep,*(edge_id*)(stacktop-1)) ) *ep = NULLID;
else *ep = eptr(*ep)->forechain;
if ( !valid_element(q_id) ) node--; /* skip body of loop */
#ifdef MPI_EVOLVER
if ( mpi_subtask_command_flag && (id_task(q_id) != this_task) )
node--; /* don't count foreign elements in global aggregate */
#endif
}
break;
case NEXT_VERTEX_EDGE_: /* vertex edges */
{ edge_id *e_ptr;
e_ptr = (element_id *)(stacktop - 0);
if ( !valid_id(*e_ptr) ) /* see if done */
{ node += node->op1.skipsize - 1;
break;
}
q_id = *e_ptr;
*(element_id*)get_localp(node->op2.localnum) = q_id;
if ( get_attr(*(element_id *)(stacktop-2)) & (Q_MIDPOINT|Q_MIDEDGE) )
*e_ptr = NULLID; /* last one */
else
{ *e_ptr = get_next_tail_edge(*e_ptr);
if ( !valid_element(*e_ptr)
|| equal_id(*e_ptr,get_vertex_edge(get_edge_tailv(*e_ptr))))
*e_ptr = NULLID; /* last one */
}
if ( !valid_element(q_id) ) node--; /* skip body of loop */
#ifdef MPI_EVOLVER
if ( mpi_subtask_command_flag && (id_task(q_id) != this_task) )
node--; /* don't count foreign elements in global aggregate */
#endif
break;
}
case NEXT_FACET_EDGE_: /* facet edges */
{
facetedge_id *fe_ptr;
fe_ptr = (element_id *)(stacktop - 0);
if ( !valid_id(*fe_ptr) ) /* see if done */
{ node += node->op1.skipsize - 1;
break;
}
q_id = get_fe_edge(*fe_ptr);
*(element_id*)get_localp(node->op2.localnum) = q_id;
*fe_ptr = get_next_edge(*fe_ptr);
if ( web.representation == STRING )
{
if ( !valid_element(*fe_ptr)
|| equal_id(*fe_ptr,*(element_id *)(stacktop-1)))
*fe_ptr = NULLID; /* last one */
}
else
{ if ( ++(*(int*)(stacktop-1)) == FACET_VERTS )
*fe_ptr = NULLID; /* last one */
}
if ( !valid_element(q_id) ) node--; /* skip body of loop */
#ifdef MPI_EVOLVER
if ( mpi_subtask_command_flag && (id_task(q_id) != this_task) )
node--; /* don't count foreign elements in global aggregate */
#endif
break;
}
case NEXT_BODY_EDGE_: /* body edges */
break;
case NEXT_FACET_: /* all facets */
{
facet_id *fp;
fp = (element_id *)(stacktop - 0);
if ( !valid_id(*fp)|| breakflag )
{ node += node->op1.skipsize - 1; /* skip to end */
break;
}
q_id = *fp;
*(element_id*)get_localp(node->op2.localnum) = q_id;
/* check sentinel; set for next time around */
if ( equal_id(*fp,*(facet_id*)(stacktop-1)) ) *fp = NULLID;
else *fp = fptr(*fp)->forechain;
if ( !valid_element(q_id) ) node--; /* skip body of loop */
#ifdef MPI_EVOLVER
if ( mpi_subtask_command_flag && (id_task(q_id) != this_task) )
node--; /* don't count foreign elements in global aggregate */
#endif
}
break;
case NEXT_EDGE_FACET_: /* all facets on edge */
{
facetedge_id *fe_ptr;
fe_ptr = (element_id *)(stacktop - 0);
if ( !valid_id(*fe_ptr) ) /* see if done */
{ node += node->op1.skipsize - 1;
break;
}
q_id = get_fe_facet(*fe_ptr);
*(element_id*)get_localp(node->op2.localnum) = q_id;
*fe_ptr = get_next_facet(*fe_ptr);
if ( !valid_element(*fe_ptr) ||
equal_element(*fe_ptr,get_edge_fe(get_fe_edge(*fe_ptr))))
*fe_ptr = NULLID; /* last one */
if ( !valid_element(q_id) ) node--; /* skip body of loop */
#ifdef MPI_EVOLVER
if ( mpi_subtask_command_flag && (id_task(q_id) != this_task) )
node--; /* don't count foreign elements in global aggregate */
#endif
break;
}
case NEXT_EDGE_FACETEDGE_: /* all facetedges on edge */
{
facetedge_id *fe_ptr;
fe_ptr = (element_id *)(stacktop - 0);
if ( !valid_id(*fe_ptr) ) /* see if done */
{ node += node->op1.skipsize - 1;
break;
}
q_id = *fe_ptr;
*(element_id*)get_localp(node->op2.localnum) = q_id;
*fe_ptr = get_next_facet(*fe_ptr);
if ( !valid_element(*fe_ptr) ||
equal_element(*fe_ptr,get_edge_fe(get_fe_edge(*fe_ptr))))
*fe_ptr = NULLID; /* last one */
if ( !valid_element(q_id) ) node--; /* skip body of loop */
#ifdef MPI_EVOLVER
if ( mpi_subtask_command_flag && (id_task(q_id) != this_task) )
node--; /* don't count foreign elements in global aggregate */
#endif
break;
}
case NEXT_VERTEX_FACET_: /* facets adjacent to vertex */
{
facet_id *f_ptr;
f_ptr = (element_id *)(stacktop - 0);
if ( !valid_id(*f_ptr) ) /* see if done */
{
node += node->op1.skipsize - 1;
break;
}
q_id = *f_ptr;
if ( id_type(q_id) == FACETEDGE )
q_id = get_fe_facet(q_id);
q_id = positive_id(q_id);
*(element_id*)get_localp(node->op2.localnum) = q_id;
v_id = *(vertex_id*)(stacktop-2);
*f_ptr=get_next_vertex_facet(v_id,*f_ptr);
if ( equal_id(*f_ptr,*(element_id*)(stacktop-1)) )
*f_ptr = NULLID;
if ( !valid_element(q_id) ) node--; /* skip body of loop */
#ifdef MPI_EVOLVER
if ( mpi_subtask_command_flag && (id_task(q_id) != this_task) )
node--; /* don't count foreign elements in global aggregate */
#endif
}
break;
case NEXT_BODY_FACET_: /* facets on body */
{
facet_id *f_ptr;
f_ptr = (element_id *)(stacktop - 0);
if ( !valid_id(*f_ptr) ) /* see if done */
{ node += node->op1.skipsize - 1;
break;
}
q_id = *f_ptr;
*(element_id*)get_localp(node->op2.localnum) = q_id;
*f_ptr = get_next_body_facet(*f_ptr);
if ( (get_fattr(*f_ptr)& (inverted(*f_ptr)?DID_BODYBACKFACET:DID_BODYFRONTFACET))
|| equal_id(*f_ptr,q_id) ||
equal_id(*f_ptr,*(element_id *)(stacktop-1)))
*f_ptr = NULLID; /* last one */
else set_attr(*f_ptr,
(inverted(*f_ptr) ? DID_BODYBACKFACET : DID_BODYFRONTFACET) );
if ( !valid_element(q_id) ) node--; /* skip body of loop */
#ifdef MPI_EVOLVER
if ( mpi_subtask_command_flag && (id_task(q_id) != this_task) )
node--; /* don't count foreign elements in global aggregate */
#endif
}
break;
case NEXT_BODY_: /* all bodies */
{
body_id *bp;
bp = (element_id *)(stacktop - 0);
if ( !valid_id(*bp)|| breakflag )
{ node += node->op1.skipsize - 1;
break;
}
q_id = *bp;
*(element_id*)get_localp(node->op2.localnum) = q_id;
/* check sentinel; set for next time around */
if ( equal_id(*bp,*(body_id*)(stacktop-1)) ) *bp = NULLID;
else *bp = bptr(*bp)->forechain;
if ( !valid_element(q_id) ) node--; /* skip body of loop */
#ifdef MPI_EVOLVER
if ( mpi_subtask_command_flag && (id_task(q_id) != this_task) )
node--; /* don't count foreign elements in global aggregate */
#endif
}
break;
case NEXT_FACET_BODY_: /* both bodies on facet */
{
int *numptr = (int *)(stacktop - 1);
f_id = *(facet_id *)(stacktop - 2); /* facet */
(*numptr)++;
if ( *numptr == 3 ) /* see if done */
{ /* done */
node += node->op1.skipsize - 1;
break;
}
if ( *numptr == 1 ) /* first */
{
q_id = get_facet_body(f_id);
*(element_id*)get_localp(node->op2.localnum) = q_id;
if ( !valid_id(q_id) )
node--; /* try again */
}
else /* *numptr == 2 */
{ q_id = get_facet_body(inverse_id(f_id));
*(element_id*)get_localp(node->op2.localnum) = q_id;
if ( !valid_id(q_id) )
node--; /* try again */
}
break;
}
case NEXT_VERTEX_BODY_: /* bodies adjacent to vertex */
break;
case NEXT_EDGE_BODY_: /* bodies adjacent to edge */
break;
case NEXT_FACETEDGE_: /* all facetedges */
{
facetedge_id *fep;
fep = (element_id *)(stacktop - 0);
if ( !valid_id(*fep)|| breakflag )
{ /* done */
node += node->op1.skipsize - 1;
break;
}
q_id = *fep;
*(element_id*)get_localp(node->op2.localnum) = q_id;
/* check sentinel; set for next time around */
if ( equal_id(*fep,*(facetedge_id*)(stacktop-1)) ) *fep = NULLID;
else *fep = feptr(*fep)->forechain;
if ( !valid_element(q_id) ) node--; /* skip body of loop */
#ifdef MPI_EVOLVER
if ( mpi_subtask_command_flag && (id_task(q_id) != this_task) )
node--; /* don't count foreign elements in global aggregate */
#endif
}
break;
case NEXT_FACETEDGE_EDGE_: /* edge on facetedge */
{
edge_id *e_ptr;
e_ptr = (element_id *)(stacktop - 0);
if ( !valid_id(*e_ptr) ) /* see if done */
{ node += node->op1.skipsize - 1;
break;
}
q_id = *e_ptr;
*(element_id*)get_localp(node->op2.localnum) = q_id;
*e_ptr = NULLID; /* last one */
if ( !valid_element(q_id) ) node--; /* skip body of loop */
#ifdef MPI_EVOLVER
if ( mpi_subtask_command_flag && (id_task(q_id) != this_task) )
node--; /* don't count foreign elements in global aggregate */
#endif
}
break;
case NEXT_FACETEDGE_FACET_: /* facet on facetedge */
{
facet_id *f_ptr;
f_ptr = (element_id *)(stacktop - 0);
if ( !valid_id(*f_ptr) ) /* see if done */
{ node += node->op1.skipsize - 1;
break;
}
q_id = *f_ptr;
*(element_id*)get_localp(node->op2.localnum) = q_id;
*f_ptr = NULLID; /* last one */
if ( !valid_element(q_id) ) node--; /* skip body of loop */
#ifdef MPI_EVOLVER
if ( mpi_subtask_command_flag && (id_task(q_id) != this_task) )
node--; /* don't count foreign elements in global aggregate */
#endif
}
break;
/***********************/
/* aggregate condition */
/***********************/
case WHERE_: /* see if element qualifies */
if ( *(stacktop--) == 0.0 )
node += node->left-1; /* no, go back to generator */
else node->op1.wherecount++; /* where count NONREENTRANT */
break; /* else continue with current element */
case SINGLE_ASSIGN_:
/* restore old q_id */
q_id = *(element_id *)(stacktop - 2);
stacktop -= 3; /* erase locals */
break;
/*****************/
/* aggregate end */
/*****************/
case AGGREGATE_END_:
aggregate_depth--;
/* restore old q_id */
q_id = *(element_id *)(stacktop - 2);
where = node+node->right;
where = where+where->left;
if ( where->type == WHERE_ )
{ web.where_count = where->op1.wherecount;
where->op1.wherecount = 0; /* reset where count */
}
switch ( node->op1.aggrtype )
{
case FOREACH_:
case SET_ATTRIBUTE_LOOP_:
stacktop -= 3; /* erase locals */
break;
case MAX_:
stacktop -= 3; /* erase locals */
#ifdef MPI_EVOLVER
if ( mpi_subtask_command_flag && (aggregate_depth==0))
{ MPI_Reduce(stacktop,stacktop+1,1,MPI_REAL,MPI_MAX,
MASTER_TASK,MPI_COMM_WORLD);
stacktop[0] = stacktop[1];
}
#endif
break;
case MIN_:
stacktop -= 3; /* erase locals */
#ifdef MPI_EVOLVER
if ( mpi_subtask_command_flag && (aggregate_depth==0))
{ MPI_Reduce(stacktop,stacktop+1,1,MPI_REAL,MPI_MIN,
MASTER_TASK,MPI_COMM_WORLD);
stacktop[0] = stacktop[1];
}
#endif
break;
case SUM_:
stacktop -= 3; /* erase locals */
#ifdef MPI_EVOLVER
if ( mpi_subtask_command_flag && (aggregate_depth==0))
{ MPI_Reduce(stacktop,stacktop+1,1,MPI_REAL,MPI_SUM,
MASTER_TASK,MPI_COMM_WORLD);
stacktop[0] = stacktop[1];
}
#endif
break;
case COUNT_:
stacktop -= 3; /* erase locals */
#ifdef MPI_EVOLVER
if ( mpi_subtask_command_flag && (aggregate_depth==0))
{ MPI_Reduce(stacktop,stacktop+1,1,MPI_REAL,MPI_SUM,
MASTER_TASK,MPI_COMM_WORLD);
stacktop[0] = stacktop[1];
}
#endif
break;
case AVG_:
stacktop -= 4; /* erase locals */
#ifdef MPI_EVOLVER
if ( mpi_subtask_command_flag && (aggregate_depth==0) )
{ MPI_Reduce(stacktop,stacktop+2,2,MPI_REAL,MPI_SUM,
MASTER_TASK,MPI_COMM_WORLD);
stacktop[0] = stacktop[2];
stacktop[1] = stacktop[3];
}
#endif
if ( stacktop[0] > 0.0 )
stacktop[0] = stacktop[1]/stacktop[0];
/* else leave avg as 0 */
break;
case LOGHISTOGRAM_:
case HISTOGRAM_:
{ int i;
REAL binsize;
int one_bin_flag = 0;
bins = stacktop - (HISTBINS+1) + 1 - 3;
/* find hi and lo */
hi = -MAXDOUBLE; lo = MAXDOUBLE;
for ( i = 0 ; i < histo_count ; i++ )
{ if ( histo_data[i] < lo )
if ( (node->op1.aggrtype == HISTOGRAM_) || ( histo_data[i] > 0.0) )
lo = histo_data[i];
if ( histo_data[i] > hi ) hi = histo_data[i];
}
#ifdef MPI_EVOLVER
if ( mpi_subtask_command_flag && (aggregate_depth==0))
{ /* synchronize max-min values */
DOUBLE localhi = hi,locallo = lo;
DOUBLE globalhi,globallo;
MPI_Allreduce(&localhi,&globalhi,1,MPI_REAL,MPI_MAX,
MPI_COMM_WORLD);
hi = globalhi;
MPI_Allreduce(&locallo,&globallo,1,MPI_REAL,MPI_MIN,
MPI_COMM_WORLD);
lo = globallo;
}
#endif
if (node->op1.aggrtype == HISTOGRAM_ )
{ if ( hi == lo )
{ binsize = 1.0; /* will put everything in first bin */
one_bin_flag = 1;
}
else binsize = (hi-lo)/HISTBINS;/* binsize */
}
else /* first bin for 0 values for log histogram */
{ if ( hi <= 0.0 ) binsize = 0.0;
else
{ hi = log(hi);
if ( lo <= 0.0 )
{ binsize = 1.0; lo = hi-(HISTBINS-1); }
else
{ lo = log(lo);
if ( hi == lo )
{ binsize = 1.0;
one_bin_flag = 1;
}
else
binsize = (hi-lo)/(HISTBINS-1);
}
}
}
binsize *= 1+10*machine_eps; /* for rounding margin */
if ( lo != 0.0 ) lo -= 10*machine_eps*binsize;
/* construct histogram */
for ( i = 0 ; i < histo_count ; i++ )
{ val = histo_data[i];
if ( !is_finite(val) )
k = HISTBINS; /* NaN */
else if ( node->op1.aggrtype == HISTOGRAM_ )
k = (int)((val-lo)/binsize);
else if ( val <= 0.0 ) k = 0;
else
{ val = log(val);
k = (int)((val-lo)/binsize)+1;
}
bins[k] += 1.0;
}
#ifdef MPI_EVOLVER
if ( mpi_subtask_command_flag && (aggregate_depth==0))
{ /* accumulate histogram data on master */
REAL recvbuf[HISTBINS+1];
MPI_Reduce(bins,recvbuf,HISTBINS+1,MPI_REAL,MPI_SUM,
MASTER_TASK, MPI_COMM_WORLD);
if ( this_task == MASTER_TASK )
for ( k = 0, histo_count = 0 ; k <= HISTBINS ; k++ )
{ bins[k] = recvbuf[k];
histo_count += (int)bins[k];
}
}
#endif
/* print histogram */
#ifdef MPI_EVOLVER
if ( (this_task == MASTER_TASK) || !mpi_subtask_command_flag )
#endif
{
if ( histo_count == 0 )
{
outstring("No qualifying values.\n");
stacktop -= HISTBINS+1 + 3 + 3;
break;
}
if ( one_bin_flag )
{ if (node->op1.aggrtype == HISTOGRAM_ )
sprintf(msg,"%10.5g - %10.5g %d\n",
(DOUBLE)hi,(DOUBLE)hi,histo_count);
else sprintf(msg,"%10.5g - %10.5g %d\n",
(DOUBLE)exp(hi),(DOUBLE)exp(hi),histo_count);
outstring(msg);
stacktop -= HISTBINS+1 + 3 + 3;
break;
}
if (node->op1.aggrtype == HISTOGRAM_ )
for ( n = 0 ; n < HISTBINS ; n++ )
{ sprintf(msg,"%10.5g - %10.5g %d\n",
(DOUBLE)(lo + n*binsize),(DOUBLE)(lo + (n+1)*binsize),
(int)bins[n]);
outstring(msg);
}
else /* log histogram */
{ int zeroes = (int)bins[0];
if ( zeroes )
{ sprintf(msg," <= 0.0 %d\n",zeroes);
outstring(msg);
}
if ( hi > 0 )
for ( n = 1 ; n < HISTBINS ; n++ )
{ sprintf(msg,"%10.5g - %10.5g %d\n",
(DOUBLE)(exp(lo + (n-1)*binsize)),
(DOUBLE)(exp(lo + n*binsize)),
(int)bins[n]);
outstring(msg);
}
}
if ( bins[HISTBINS] > 0.0 )
{ sprintf(msg,"NaN %d\n",(int)bins[HISTBINS]);
outstring(msg);
}
}
temp_free((char*)histo_data);
stacktop -= HISTBINS+1 + 3 + 3; /* erase locals */
mpi_subtask_command_flag = 0;
break;
}
case LIST_:
stacktop -= 3; /* erase locals */
break;
case SET_COLOR_:
case SET_FRONTCOLOR_:
case SET_BACKCOLOR_:
case SET_OPACITY_:
stacktop -= 3; /* erase locals */
update_display_flag = 1;
break;
case SET_FIXED_: case SET_NO_REFINE_: case SET_NO_DISPLAY_:
case SET_DENSITY_: case UNSET_DENSITY_: case SET_BARE_:
case SET_CONSTRAINT_: case UNSET_CONSTRAINT_:
case SET_CONSTRAINT_NAME: case UNSET_CONSTRAINT_NAME:
case SET_VOLUME_: case SET_PRESSURE_: case SET_NONCONTENT_:
case UNSET_BOUNDARY_: case UNSET_BOUNDARY_NAME:
case UNSET_FIXED_: case UNSET_PRESSURE_: case UNSET_VOLUME_:
case SET_NAMED_QUANTITY_: case UNSET_NO_REFINE_: case UNSET_BARE_:
case UNSET_NAMED_QUANTITY_: case UNSET_NO_DISPLAY_:
case SET_METHOD_INSTANCE_: case UNSET_METHOD_INSTANCE_:
case UNSET_TRIPLE_PT_: case UNSET_TETRA_PT_:
case UNSET_NONCONTENT_: case SET_BOUNDARY_:
case SET_HIT_PARTNER_: case UNSET_HIT_PARTNER_:
stacktop -= 3; /* erase locals */
recalc_flag = 1;
break;
case SET_FRONTBODY_:
case SET_BACKBODY_:
case UNSET_FRONTBODY_:
case UNSET_BACKBODY_:
case UNSET_FACET_BODY_:
/*make_bfacet_lists(); */ /* so lists legal */
stacktop -= 3; /* erase locals */
recalc_flag = 1;
break;
case REFINE_:
stacktop -= 3; /* erase locals */
#ifdef MPI_EVOLVER
if ( (this_task != MASTER_TASK) && mpi_subtask_command_flag )
mpi_task_edge_refine_wrapup();
#endif
break;
case DISSOLVE_:
stacktop -= 3; /* erase locals */
break;
case DELETE_:
stacktop -= 3; /* erase locals */
#ifdef MPI_EVOLVER
if ( (this_task != MASTER_TASK) && mpi_subtask_command_flag )
mpi_task_delete_wrapup();
#endif
break;
case FIX_:
stacktop -= 3; /* erase locals */
break;
case UNFIX_:
stacktop -= 3; /* erase locals */
break;
default:
stacktop -= 3; /* erase locals */
break;
} break; /* end AGGREGATE_END */
/*********************/
/* attribute setting */
/* aggregate verbs */
/*********************/
case SET_FIXED_:
set_attr(q_id,FIXED);
/* go back to next element generator */
node += node->op1.skipsize - 1; /* back to start of loop */
break;
case UNSET_FIXED_:
unset_attr(q_id,FIXED);
/* go back to next element generator */
node += node->op1.skipsize - 1; /* back to start of loop */
break;
case SET_BARE_:
set_attr(q_id,BARE_NAKED);
/* go back to next element generator */
node += node->op1.skipsize - 1; /* back to start of loop */
break;
case UNSET_BARE_:
unset_attr(q_id,BARE_NAKED);
/* go back to next element generator */
node += node->op1.skipsize - 1; /* back to start of loop */
break;
case SET_NO_DISPLAY_:
set_attr(q_id,NODISPLAY);
/* go back to next element generator */
node += node->op1.skipsize - 1; /* back to start of loop */
break;
case UNSET_NO_DISPLAY_:
unset_attr(q_id,NODISPLAY);
/* go back to next element generator */
node += node->op1.skipsize - 1; /* back to start of loop */
break;
case SET_NONCONTENT_:
if ( everything_quantities_flag )
kb_error(2484,
"Changing NONCONTENT not implemented for everything_quantities mode yet.\n",
RECOVERABLE);
set_attr(q_id,NONCONTENT);
/* go back to next element generator */
node += node->op1.skipsize - 1; /* back to start of loop */
break;
case UNSET_NONCONTENT_:
if ( everything_quantities_flag )
kb_error(2595,
"Changing NONCONTENT not implemented for everything_quantities mode yet.\n",
RECOVERABLE);
unset_attr(q_id,NONCONTENT);
/* go back to next element generator */
node += node->op1.skipsize - 1; /* back to start of loop */
break;
case SET_HIT_PARTNER_:
set_attr(q_id,HIT_PARTNER);
/* go back to next element generator */
node += node->op1.skipsize - 1; /* back to start of loop */
break;
case UNSET_HIT_PARTNER_:
unset_attr(q_id,HIT_PARTNER);
/* go back to next element generator */
node += node->op1.skipsize - 1; /* back to start of loop */
break;
case SET_NO_REFINE_:
set_attr(q_id,NO_REFINE);
/* go back to next element generator */
node += node->op1.skipsize - 1; /* back to start of loop */
break;
case UNSET_NO_REFINE_:
unset_attr(q_id,NO_REFINE);
/* go back to next element generator */
node += node->op1.skipsize - 1; /* back to start of loop */
break;
case UNSET_PRESSURE_:
unset_attr(q_id,PRESSURE);
if ( everything_quantities_flag )
{ struct gen_quant *q = GEN_QUANT(get_body_volquant(q_id));
q->modulus = 1;
q->flags &= ~(Q_ENERGY|Q_FIXED|Q_CONSERVED);
q->flags |= Q_INFO;
}
/* go back to next element generator */
node += node->op1.skipsize - 1; /* back to start of loop */
break;
case UNSET_CONSTRAINT_:
case UNSET_CONSTRAINT_NAME:
if (node->type == UNSET_CONSTRAINT_)
k = (int)*(stacktop--);
else
k = node->op3.connum;
k &= CONMASK; /* so will ignore hit bit */
if ( k < web.maxcon )
switch ( id_type(q_id) )
{ case VERTEX:
unset_v_constraint_map(q_id,k);
break;
case EDGE:
unset_e_constraint_map(q_id,k);
break;
case FACET:
unset_f_constraint_map(q_id,k);
break;
default:
sprintf(errmsg,"Bad element type for constraint.\n");
sprintf(errmsg+strlen(errmsg),"(source file %s, line %d)\n",
file_names[node->file_no],node->line_no);
kb_error(1292,errmsg, RECOVERABLE);
}
/* go back to next element generator */
node += node->op1.skipsize - 1; /* back to start of loop */
break;
case SET_BOUNDARY_:
k = (int)*(stacktop--); /* boundary number */
bdry = web.boundaries+abs(k);
if ( (abs(k) >= web.bdrymax) || !(bdry->attr&IN_USE) )
{ sprintf(errmsg,"Boundary %d is not valid.\n",k);
kb_error(2998,errmsg,RECOVERABLE);
}
if ( get_attr(q_id) & BOUNDARY )
{ struct boundary *qbdry;
switch ( id_type(q_id) )
{ case VERTEX: qbdry = get_boundary(q_id); break;
case EDGE: qbdry = get_edge_boundary(q_id); break;
case FACET: qbdry = get_facet_boundary(q_id); break;
default: qbdry = NULL; /* error message below */
}
if ( qbdry == bdry ) break;
sprintf(errmsg,"%s %s already on a different boundary.\n",
typenames[id_type(q_id)],ELNAME(q_id));
kb_error(2999,errmsg,RECOVERABLE);
}
set_attr(q_id,BOUNDARY);
if ( k < 0 )
set_attr(q_id,NEGBOUNDARY);
switch(id_type(q_id))
{ case VERTEX:
{ REAL *x = get_coord(q_id);
int n;
set_boundary_num(q_id,abs(k));
for ( n = 0 ; n < SDIM ; n++ )
if ( bdry->coordf[n]->root != NULL )
{ PROF_EVAL_END(ex);
x[n] = eval(bdry->coordf[n],get_param(q_id),q_id,NULL);
PROF_EVAL_START(ex);
}
break;
}
case EDGE:
set_edge_boundary_num(q_id,abs(k));
break;
case FACET:
set_facet_boundary_num(q_id,abs(k));
break;
default:
sprintf(errmsg,"Bad element type for boundary.\n");
sprintf(errmsg+strlen(errmsg),"(source file %s, line %d)\n",
file_names[node->file_no],node->line_no);
kb_error(3000,errmsg, RECOVERABLE);
}
if ( bdry->attr & CON_ENERGY )
apply_method_num(q_id,bdry->energy_method);
if ( bdry->attr & CON_CONTENT )
{ if ( (web.representation == STRING) && (id_type(q_id) == VERTEX) )
fixup_vertex_content_meths(q_id);
else if ( (web.representation == SOAPFILM) && (id_type(q_id) == EDGE) )
fixup_edge_content_meths(q_id);
}
/* go back to next element generator */
node += node->op1.skipsize - 1; /* back to start of loop */
break;
case UNSET_BOUNDARY_:
case UNSET_BOUNDARY_NAME:
k = (node->type == UNSET_BOUNDARY_) ? (int)*(stacktop--)
: node->op3.bdrynum;
if ( k >= web.bdrymax ) break;
bdry = web.boundaries+k;
if ( get_attr(q_id) & BOUNDARY )
{
switch ( id_type(q_id) )
{ case VERTEX:
if ( get_boundary(q_id) == bdry )
{ set_boundary_num(q_id,0);
unset_attr(q_id,BOUNDARY|HIT_PARTNER);
}
break;
case EDGE:
if ( get_edge_boundary(q_id) == bdry )
{ set_edge_boundary_num(q_id,0);
unset_attr(q_id,BOUNDARY);
}
break;
case FACET:
if ( get_facet_boundary(q_id) == bdry )
{ set_facet_boundary_num(q_id,0);
unset_attr(q_id,BOUNDARY);
}
break;
default:
sprintf(errmsg,"Bad element type for boundary.\n");
sprintf(errmsg+strlen(errmsg),"(source file %s, line %d)\n",
file_names[node->file_no],node->line_no);
kb_error(1293,errmsg, RECOVERABLE);
}
if ( bdry->attr & CON_ENERGY )
unapply_method(q_id,bdry->energy_method);
if ( bdry->attr & CON_CONTENT )
{ if ( (web.representation == STRING) && (id_type(q_id) == VERTEX) )
fixup_vertex_content_meths(q_id);
else if ( (web.representation == SOAPFILM) && (id_type(q_id) == EDGE) )
fixup_edge_content_meths(q_id);
}
}
/* go back to next element generator */
node += node->op1.skipsize - 1; /* back to start of loop */
break;
case UNSET_VOLUME_:
case UNSET_TARGET_:
if ( get_attr(q_id) & FIXEDVOL)
{ unset_attr(q_id,FIXEDVOL);
if (everything_quantities_flag )
{ struct gen_quant *q = GEN_QUANT(get_body_volquant(q_id));
q->target = 0.0;
if ( !(q->flags & Q_INFO) )
{ q->flags &= ~(Q_FIXED|Q_ENERGY|Q_CONSERVED);
q->flags |= Q_INFO;
}
if ( web.pressure_flag )
{ q = GEN_QUANT(get_body_ambquant(q_id));
q->flags &= ~(Q_FIXED|Q_ENERGY|Q_CONSERVED);
q->flags |= Q_INFO;
}
}
}
/* go back to next element generator */
node += node->op1.skipsize - 1; /* back to start of loop */
break;
case UNSET_FACET_BODY_:
if ( id_type(q_id) != FACET )
{ sprintf(errmsg,"Trying to unset body of non-facet.\n");
sprintf(errmsg+strlen(errmsg),"(source file %s, line %d)\n",
file_names[node->file_no],node->line_no);
kb_error(1294,errmsg, RECOVERABLE);
}
set_facet_body(q_id,NULLID);
set_facet_body(inverse_id(q_id),NULLID);
/* go back to next element generator */
node += node->op1.skipsize - 1; /* back to start of loop */
break;
case UNSET_FRONTBODY_:
case UNSET_BACKBODY_:
set_body(node->type==UNSET_FRONTBODY_?q_id:inverse_id(q_id),NULLID);
recalc_flag = 1;
node += node->op1.skipsize - 1; /* back to start of loop */
break;
case UNSET_DENSITY_:
unset_attr(q_id,DENSITY);
/* go back to next element generator */
node += node->op1.skipsize - 1; /* back to start of loop */
break;
case UNSET_TRIPLE_PT_:
unset_attr(q_id,TRIPLE_PT);
/* go back to next element generator */
node += node->op1.skipsize - 1; /* back to start of loop */
break;
case UNSET_TETRA_PT_:
unset_attr(q_id,TETRA_PT);
/* go back to next element generator */
node += node->op1.skipsize - 1; /* back to start of loop */
break;
case UNSET_AXIAL_POINT_:
unset_attr(q_id,AXIAL_POINT);
/* go back to next element generator */
node += node->op1.skipsize - 1; /* back to start of loop */
break;
case SET_DENSITY_:
{ REAL density = *(stacktop--);
if ( density != 1.0 ) set_attr(q_id,DENSITY);
switch ( node->op2.eltype )
{ case EDGE: set_edge_density(q_id,density); break;
case FACET: set_facet_density(q_id,density); break;
case BODY: set_body_density(q_id,density); break;
}
/* go back to next element generator */
node += node->op1.skipsize - 1; /* back to start of loop */
}
break;
case SET_VOLUME_:
{ REAL v = *(stacktop--);
if ( get_attr(q_id) & PRESSURE )
{ sprintf(errmsg,"Must unset body pressure before fixing target.\n");
sprintf(errmsg+strlen(errmsg),"(source file %s, line %d)\n",
file_names[node->file_no],node->line_no);
kb_error(2071,errmsg, RECOVERABLE);
}
set_attr(q_id,FIXEDVOL);
set_body_fixvol(q_id,v);
/* go back to next element generator */
node += node->op1.skipsize - 1; /* back to start of loop */
break;
}
case SET_PRESSURE_:
{ REAL p = *(stacktop--);
if ( get_attr(q_id) & FIXEDVOL )
{ sprintf(errmsg,"Must unset body target before fixing pressure.\n");
sprintf(errmsg+strlen(errmsg),"(source file %s, line %d)\n",
file_names[node->file_no],node->line_no);
kb_error(2521,errmsg, RECOVERABLE);
}
set_attr(q_id,PRESSURE);
set_body_pressure(q_id,p);
if ( everything_quantities_flag )
{ struct gen_quant *q = GEN_QUANT(get_body_volquant(q_id));
q->modulus = -p;
if ( !(q->flags & Q_ENERGY) )
{ q->flags &= ~(Q_INFO|Q_FIXED|Q_CONSERVED);
q->flags |= Q_ENERGY;
}
}
/* go back to next element generator */
node += node->op1.skipsize - 1; /* back to start of loop */
break;
}
case SET_OPACITY_:
facet_alpha = *(stacktop)--;
/* go back to next element generator */
node += node->op1.skipsize - 1; /* back to start of loop */
break;
case SET_CONSTRAINT_:
case SET_CONSTRAINT_NAME:
{ int con = (node->type==SET_CONSTRAINT_) ? (int)*(stacktop--)
: node->op3.connum;
if ( (con<0) || (con>=web.maxcon) || !(get_constraint(con)->attr & IN_USE))
{ sprintf(errmsg,"Illegal constraint number: %d.\n",con);
sprintf(errmsg+strlen(errmsg),"(source file %s, line %d)\n",
file_names[node->file_no],node->line_no);
kb_error(1295,errmsg,RECOVERABLE);
}
if ( get_attr(q_id) & BOUNDARY )
{ sprintf(errmsg,
"Cannot set %s %s on a constraint since it is on a boundary.\n",
typenames[node->op2.eltype],ELNAME(q_id));
kb_error(4002,errmsg,RECOVERABLE);
}
switch ( node->op2.eltype )
{ case VERTEX: set_v_constraint_map(q_id,con);
project_v_constr(q_id,ACTUAL_MOVE,RESET_ONESIDEDNESS);
break;
case EDGE: set_e_constraint_map(q_id,con); break;
case FACET: set_f_constraint_map(q_id,con); break;
}
/* go back to next element generator */
node += node->op1.skipsize - 1; /* back to start of loop */
}
break;
case SET_NAMED_QUANTITY_:
{ int qnum = (int)*(stacktop--);
apply_quantity(q_id,qnum);
/* go back to next element generator */
node += node->op1.skipsize - 1; /* back to start of loop */
}
break;
case UNSET_NAMED_QUANTITY_:
{ int qnum = (int)*(stacktop--);
unapply_quantity(q_id,qnum);
/* go back to next element generator */
node += node->op1.skipsize - 1; /* back to start of loop */
}
break;
case SET_METHOD_INSTANCE_:
{ int qnum = (int)*(stacktop--);
apply_method_num(q_id,qnum);
/* go back to next element generator */
node += node->op1.skipsize - 1; /* back to start of loop */
}
break;
case UNSET_METHOD_INSTANCE_:
{ int qnum = (int)*(stacktop--);
unapply_method(q_id,qnum);
/* go back to next element generator */
node += node->op1.skipsize - 1; /* back to start of loop */
}
break;
case SET_COLOR_:
{ int color = (int)*(stacktop--);
switch ( node->op2.eltype )
{ case EDGE: set_edge_color(q_id,color); break;
case FACET: set_facet_color(q_id,color); break;
}
/* go back to next element generator */
node += node->op1.skipsize - 1; /* back to start of loop */
update_display_flag = 1;
}
break;
case SET_FRONTCOLOR_:
{ int color = (int)*(stacktop--);
set_facet_frontcolor(q_id,color);
/* go back to next element generator */
node += node->op1.skipsize - 1; /* back to start of loop */
update_display_flag = 1;
}
break;
case SET_BACKCOLOR_:
{ int color = (int)*(stacktop--);
set_facet_backcolor(q_id,color);
/* go back to next element generator */
node += node->op1.skipsize - 1; /* back to start of loop */
update_display_flag = 1;
}
break;
case SET_TAG_:
{ int tag = (int)*(stacktop--);
switch ( node->op2.eltype )
{
case FACET: set_tag(q_id,tag); break;
}
/* go back to next element generator */
node += node->op1.skipsize - 1; /* back to start of loop */
}
break;
case SET_COORD_:
get_coord(q_id)[node->op2.coordnum] = *(stacktop--);
if ( node->op2.coordnum <= SDIM ) recalc_flag = 1;
/* go back to next element generator */
node += node->op1.skipsize - 1; /* back to start of loop */
break;
case SET_PARAM_:
if ( get_vattr(q_id) & BOUNDARY )
{ struct boundary *boundary = get_boundary(q_id);
REAL *param = get_param(q_id);
REAL *xx = get_coord(q_id);
if ( node->op2.coordnum > boundary->pcount )
{ sprintf(errmsg,"Parameter number is %d; maximum is %d.\n",
node->op2.coordnum,boundary->pcount);
sprintf(errmsg+strlen(errmsg),"(source file %s, line %d)\n",
file_names[node->file_no],node->line_no);
kb_error(1296,errmsg,RECOVERABLE);
}
param[node->op2.coordnum] = *(stacktop--);
PROF_EVAL_END(ex);
for ( k = 0 ; k < SDIM ; k++ )
xx[k] = eval(boundary->coordf[k],param,q_id,NULL);
PROF_EVAL_START(ex);
recalc_flag = 1;
}
else
{ /* probably just handy for storage */
REAL *param = get_param(q_id);
param[node->op2.coordnum] = *(stacktop--);
}
/* go back to next element generator */
node += node->op1.skipsize - 1; /* back to start of loop */
break;
/************************/
/* numerical aggregates */
/************************/
case MAX_:
{ REAL *aggrptr;
val = *(stacktop--);
aggrptr = (REAL *)(stacktop - 3);
if ( val > *aggrptr ) *aggrptr = val;
/* go back to next element generator */
node += node->op1.skipsize - 1; /* back to start of loop */
}
break;
case MIN_:
{
REAL *aggrptr;
val = *(stacktop--);
aggrptr = (REAL *)(stacktop - 3);
if ( val < *aggrptr ) *aggrptr = val;
/* go back to next element generator */
node += node->op1.skipsize - 1; /* back to start of loop */
}
break;
case SUM_:
stacktop--;
stacktop[-3] += stacktop[1];
/* go back to next element generator */
node += node->op1.skipsize - 1; /* back to start of loop */
break;
case AVG_:
stacktop--;
stacktop[-3] += stacktop[1]; /* sum */
stacktop[-4] += 1.0; /* count */
/* go back to next element generator */
node += node->op1.skipsize - 1; /* back to start of loop */
break;
case COUNT_:
stacktop--;
stacktop[-3] += 1.0;
/* go back to next element generator */
node += node->op1.skipsize - 1; /* back to start of loop */
break;
case HISTOGRAM_:
case LOGHISTOGRAM_:
if ( histo_count >= histo_max )
{ histo_data = (REAL*)temp_realloc((char*)histo_data,
2*histo_max*sizeof(REAL));
histo_max *= 2;
}
histo_data[histo_count++] = *(stacktop--);
node += node->op1.skipsize - 1; /* back to start of loop */
break;
case FOREACH_:
case SET_ATTRIBUTE_LOOP_:
node += node->op1.skipsize - 1; /* back to start of loop */
break;
case ARRAY_HEAD_: break; /* let indices accumulate */
case ARRAYASSIGN:
{ struct array *a;
REAL value=0.0,rhs;
int i,offset;
void *lvalue;
struct global *g = globals(node->op2.name_id);
a = get_name_arrayptr(node->op2.name_id,localstack,localbase);
rhs = *(stacktop--);
for ( i = 0 ; i < a->dim ; i++ )
{ int k = (int)stacktop[i+1-a->dim];
if ( k < 1 )
{ sprintf(errmsg,
"Array index %d of array %s is %d. Indexes start at 1.\n",
i+1,g->name,k);
sprintf(errmsg+strlen(errmsg),"(source file %s, line %d)\n",
file_names[node->file_no],node->line_no);
kb_error(3011,errmsg,RECOVERABLE);
}
if ( k > a->sizes[i] && (!(node->flags & IS_VIRTUAL_ATTR) ||(k > SDIM)) )
{ sprintf(errmsg,"Array index %d of array %s is %d; exceeds bound of %d.\n",
i+1,g->name,k,a->sizes[i]);
sprintf(errmsg+strlen(errmsg),"(source file %s, line %d)\n",
file_names[node->file_no],node->line_no);
kb_error(3012,errmsg,RECOVERABLE);
}
}
for ( i = 1, offset = (int)stacktop[1-a->dim]-1 ; i < a->dim ; i++ )
{ offset *= a->sizes[i];
offset += (int)stacktop[i+1-a->dim]-1; /* 1-based indexing */
}
stacktop -= a->dim;
lvalue = ((char *)a) + a->datastart + offset*a->itemsize;
switch ( a->datatype )
{ case REAL_TYPE: value = *(REAL*)(lvalue); break;
case INTEGER_TYPE: value = *(int*)(lvalue); break;
case UINT_TYPE: value = *(unsigned int*)(lvalue); break;
case SHORT_TYPE: value = *(short int*)(lvalue); break;
case USHORT_TYPE: value = *(unsigned short int*)(lvalue); break;
case LONG_TYPE: value = *(long int*)(lvalue); break;
case ULONG_TYPE: value = *(unsigned long int*)(lvalue); break;
case CHAR_TYPE: value = *(char*)(lvalue); break;
case UCHAR_TYPE: value = *(unsigned char*)(lvalue); break;
case PTR_TYPE: value = (unsigned long int)*(char**)(lvalue); break;
case VERTEX_TYPE:
case EDGE_TYPE:
case FACET_TYPE:
case BODY_TYPE:
case FACETEDGE_TYPE:
case ELEMENTID_TYPE: break;
default: value = *(int*)(lvalue); break;
}
switch ( node->op1.assigntype )
{
case ASSIGN_: value = rhs; break;
case PLUSASSIGN_: value += rhs; break;
case SUBASSIGN_: value -= rhs; break;
case MULTASSIGN_: value *= rhs; break;
case DIVASSIGN_:
if( rhs == 0.0 )
{ sprintf(errmsg,"Division by zero.\n");
sprintf(errmsg+strlen(errmsg),"(source file %s, line %d)\n",
file_names[node->file_no],node->line_no);
kb_error(3015,errmsg,RECOVERABLE);
}
value /= rhs; break;
}
switch ( a->datatype )
{ case REAL_TYPE: *(REAL*)(lvalue) = value; break;
case INTEGER_TYPE: *(int*)(lvalue) = (int)value; break;
case UINT_TYPE: *(unsigned int*)(lvalue) = (unsigned int)value; break;
case CHAR_TYPE: *(char*)(lvalue) = (char)value; break;
case UCHAR_TYPE: *(unsigned char*)(lvalue) = (unsigned char)value; break;
case SHORT_TYPE: *(short*)(lvalue) = (short)value; break;
case USHORT_TYPE: *(unsigned short*)(lvalue) = (unsigned short)value; break;
case LONG_TYPE: *(long*)(lvalue) = (long)value; break;
case ULONG_TYPE: *(unsigned long*)(lvalue) = (unsigned long)value; break;
case VERTEX_TYPE:
case EDGE_TYPE:
case FACET_TYPE:
case BODY_TYPE:
case FACETEDGE_TYPE:
case ELEMENTID_TYPE: break;
default: *(int*)(lvalue) = (int)value; break;
}
if ( g->flags & RECALC_PARAMETER )
recalc_flag = 1;
}
break;
case ARRAYEVAL:
{
struct global *g = globals(node->op2.name_id);
struct array *a;
REAL value=0.0;
int i,offset;
void *lvalue;
a = get_name_arrayptr(node->op2.name_id,localstack,localbase);
for ( i = 0 ; i < a->dim ; i++ )
{ int k = (int)stacktop[i+1-a->dim];
if ( k < 1 )
{ sprintf(errmsg,
"Array index %d of array %s is %d. Indexes start at 1.\n",
i+1,g->name,k);
sprintf(errmsg+strlen(errmsg),"(source file %s, line %d)\n",
file_names[node->file_no],node->line_no);
kb_error(2047,errmsg,RECOVERABLE);
}
if ( k > a->sizes[i] )
{ sprintf(errmsg,
"Array index %d of array %s is %d; exceeds bound of %d.\n",
i+1,g->name,k,a->sizes[i]);
sprintf(errmsg+strlen(errmsg),"(source file %s, line %d)\n",
file_names[node->file_no],node->line_no);
kb_error(2048,errmsg,RECOVERABLE);
}
}
for ( i = 1, offset = (int)stacktop[1-a->dim]-1 ; i < a->dim ; i++ )
{ offset *= a->sizes[i];
offset += (int)stacktop[i+1-a->dim]-1; /* 1-based indexing */
}
stacktop -= a->dim;
lvalue = ((char *)a) + a->datastart + offset*a->itemsize;
switch ( a->datatype )
{ case REAL_TYPE: value = *(REAL*)(lvalue); break;
case INTEGER_TYPE: value = *(int*)(lvalue); break;
case UINT_TYPE: value = *(unsigned int*)(lvalue); break;
case CHAR_TYPE: value = *(char*)(lvalue); break;
case UCHAR_TYPE: value = *(unsigned char*)(lvalue); break;
case SHORT_TYPE: value = *(short int*)(lvalue); break;
case USHORT_TYPE: value = *(unsigned short int*)(lvalue); break;
case LONG_TYPE: value = *(long*)(lvalue); break;
case ULONG_TYPE: value = *(unsigned long*)(lvalue); break;
case PTR_TYPE: value = (unsigned long)*(char**)(lvalue); break;
case VERTEX_TYPE:
case EDGE_TYPE:
case FACET_TYPE:
case BODY_TYPE:
case FACETEDGE_TYPE:
case ELEMENTID_TYPE: value = (int)*(element_id*)(lvalue); break;
default: value = *(int*)(lvalue); break;
}
*(++stacktop) = value;
}
break;
/* whole array syntax */
case ARRAYIDENT_: /* push datastart for array */
{ struct global *glvalue = globals(node->op2.name_id);
struct array *alvalue;
alvalue = get_name_arrayptr(node->op2.name_id,localstack,localbase);
if ( glvalue->flags & FIXED_SIZE_ARRAY )
*(REAL**)(++stacktop) =
localstack + glvalue->attr.arrayptr->datastart;
else
*(char**)(++stacktop) = (char*)alvalue + alvalue->datastart;
break;
}
case ATTRIB_LVALUE_: /* push datastart for attribute array */
{ element_id id;
n = node->op2.name_id & GLOBMASK; /* attribute number */
if ( node->op1.localnum )
id = *(element_id*)get_localp(node->op1.localnum);
else id = q_id;
*(char**)(++stacktop) = (char*)get_extra(id,n);
}
break;
case ARRAY_VERTEX_NORMAL_:
case ARRAY_EDGE_VECTOR_:
case ARRAY_FACET_NORMAL_:
{ element_id id;
REAL *datastart = get_localp(node->op3.localnum);
*(REAL**)(++stacktop) = datastart;
if ( node->flags & IS_RVALUE )
{ if ( node->op1.localnum )
id = *(element_id*)get_localp(node->op1.localnum);
else id = q_id;
switch ( node->type )
{ case ARRAY_VERTEX_NORMAL_:
{ MAT2D(normal,MAXCOORD,MAXCOORD);
REAL mag;
int normcount;
normcount = new_calc_vertex_normal(id,normal);
project_vertex_normals(id,normal,normcount);
mag = sqrt(SDIM_dot(normal[0],normal[0]));
if ( mag == 0.0 ) mag = 1;
for ( i = 0 ; i < SDIM ; i++ )
datastart[i] = normal[0][i]/mag;
break;
}
case ARRAY_EDGE_VECTOR_:
get_edge_side(id,datastart);
break;
case ARRAY_FACET_NORMAL_:
get_facet_normal(id,datastart);
break;
}
}
}
break;
case ARRAY_LVALUE_INDEXED_:
break;
case ARRAY_RVALUE_ :
break;
case DOT_: /* dot product */
{ struct array *a,*b;
int name1 = node->op2.name_id;
int name2 = node->op3.name_id;
REAL *datastart1,*datastart2;
REAL sum;
int counta,countb,count;
if ( node[node->left].flags & IS_VIRTUAL_ATTR )
counta = SDIM;
else
{ a = get_name_arrayptr(name1,NULL,localbase);
counta = a->datacount;
}
if ( node[node->right].flags & IS_VIRTUAL_ATTR )
countb = SDIM;
else
{ b = get_name_arrayptr(name2,NULL,localbase);
countb = b->datacount;
}
count = (counta < countb) ? counta : countb;
datastart1 = *(REAL**)(stacktop--);
datastart2 = *(REAL**)(stacktop--);
for ( sum = 0.0, i = 0 ; i < count ; i++ )
sum += datastart1[i]*datastart2[i];
*(++stacktop) = sum;
break;
}
case ARRAY_EVAL_: /* rexpr: arraylvalue indexset */
{ /* use info on stack to push value of array element.
stack: datastart index-values -> rexpr */
struct array *a;
REAL value=0.0;
int i,offset;
void *lvalue;
char *datastart;
a = get_name_arrayptr(node->op2.name_id,localstack,localbase);
for ( i = 0 ; i < a->dim ; i++ )
{ int k = (int)stacktop[i+1-a->dim];
if ( k < 1 )
{ sprintf(errmsg,
"Array index %d of array %s is %d. Indexes start at 1.\n",
i+1,get_name_name(node->op2.name_id,localbase),k);
sprintf(errmsg+strlen(errmsg),"(source file %s, line %d)\n",
file_names[node->file_no],node->line_no);
kb_error(3022,errmsg,RECOVERABLE);
}
if ( k > a->sizes[i] && (!(node->flags & IS_VIRTUAL_ATTR) ||(k > SDIM)) )
{sprintf(errmsg,"Array index %d of array %s is %d; exceeds bound of %d.\n",
i+1,get_name_name(node->op2.name_id,localbase),k,a->sizes[i]);
sprintf(errmsg+strlen(errmsg),"(source file %s, line %d)\n",
file_names[node->file_no],node->line_no);
kb_error(3023,errmsg,RECOVERABLE);
}
}
for ( i = 1, offset = (int)stacktop[1-a->dim]-1 ; i < a->dim ; i++ )
{ offset *= a->sizes[i];
offset += (int)stacktop[i+1-a->dim]-1; /* 1-based indexing */
}
stacktop -= a->dim;
datastart = *(char**)(stacktop--);
lvalue = datastart + offset*a->itemsize;
switch ( a->datatype )
{ case REAL_TYPE: value = *(REAL*)(lvalue); break;
case INTEGER_TYPE: value = *(int*)(lvalue); break;
case UINT_TYPE: value = *(unsigned int*)(lvalue); break;
case SHORT_TYPE: value = *(short int*)(lvalue); break;
case USHORT_TYPE: value = *(unsigned short int*)(lvalue); break;
case LONG_TYPE: value = *(long int*)(lvalue); break;
case ULONG_TYPE: value = *(unsigned long int*)(lvalue); break;
case CHAR_TYPE: value = *(char*)(lvalue); break;
case UCHAR_TYPE: value = *(unsigned char*)(lvalue); break;
case PTR_TYPE: value = (unsigned long int)*(char**)(lvalue); break;
case VERTEX_TYPE:
case EDGE_TYPE:
case FACET_TYPE:
case BODY_TYPE:
case FACETEDGE_TYPE:
case ELEMENTID_TYPE: break;
default: value = *(int*)(lvalue); break;
}
*(++stacktop) = value;
break;
}
case ARRAY_ASSIGNOP_SINGLE_:
{ /* use info on stack to assign value to array element.
stack: datastart index-values rexpr */
struct array *a;
REAL value=0.0,rhs;
int i,offset;
void *lvalue;
char *datastart;
a = get_name_arrayptr(node->op2.name_id,localstack,localbase);
rhs = *(stacktop--);
for ( i = 0 ; i < a->dim ; i++ )
{ int k = (int)stacktop[i+1-a->dim];
if ( k < 1 )
{ sprintf(errmsg,
"Array index %d of array %s is %d. Indexes start at 1.\n",
i+1,get_name_name(node->op2.name_id,localbase),k);
sprintf(errmsg+strlen(errmsg),"(source file %s, line %d)\n",
file_names[node->file_no],node->line_no);
kb_error(2045,errmsg,RECOVERABLE);
}
if ( k > a->sizes[i] && (!(node->flags & IS_VIRTUAL_ATTR) ||(k > SDIM)) )
{ sprintf(errmsg,"Array index %d of array %s is %d; exceeds bound of %d.\n",
i+1,get_name_name(node->op2.name_id,localbase),k,a->sizes[i]);
sprintf(errmsg+strlen(errmsg),"(source file %s, line %d)\n",
file_names[node->file_no],node->line_no);
kb_error(2046,errmsg,RECOVERABLE);
}
}
for ( i = 1, offset = (int)stacktop[1-a->dim]-1 ; i < a->dim ; i++ )
{ offset *= a->sizes[i];
offset += (int)stacktop[i+1-a->dim]-1; /* 1-based indexing */
}
stacktop -= a->dim;
datastart = *(char**)(stacktop--);
lvalue = datastart + offset*a->itemsize;
switch ( a->datatype )
{ case REAL_TYPE: value = *(REAL*)(lvalue); break;
case INTEGER_TYPE: value = *(int*)(lvalue); break;
case UINT_TYPE: value = *(unsigned int*)(lvalue); break;
case SHORT_TYPE: value = *(short int*)(lvalue); break;
case USHORT_TYPE: value = *(unsigned short int*)(lvalue); break;
case LONG_TYPE: value = *(long int*)(lvalue); break;
case ULONG_TYPE: value = *(unsigned long int*)(lvalue); break;
case CHAR_TYPE: value = *(char*)(lvalue); break;
case UCHAR_TYPE: value = *(unsigned char*)(lvalue); break;
case PTR_TYPE: value = (unsigned long int)*(char**)(lvalue); break;
case VERTEX_TYPE:
case EDGE_TYPE:
case FACET_TYPE:
case BODY_TYPE:
case FACETEDGE_TYPE:
case ELEMENTID_TYPE: break;
default: value = *(int*)(lvalue); break;
}
switch ( node->op1.assigntype )
{
case ASSIGN_: value = rhs; break;
case PLUSASSIGN_: value += rhs; break;
case SUBASSIGN_: value -= rhs; break;
case MULTASSIGN_: value *= rhs; break;
case DIVASSIGN_:
if( rhs == 0.0 )
{ sprintf(errmsg,"Division by zero.\n");
sprintf(errmsg+strlen(errmsg),"(source file %s, line %d)\n",
file_names[node->file_no],node->line_no);
kb_error(2564,errmsg,RECOVERABLE);
}
value /= rhs; break;
}
switch ( a->datatype )
{ case REAL_TYPE: *(REAL*)(lvalue) = value; break;
case INTEGER_TYPE: *(int*)(lvalue) = (int)value; break;
case UINT_TYPE: *(unsigned int*)(lvalue) = (unsigned int)value; break;
case CHAR_TYPE: *(char*)(lvalue) = (char)value; break;
case UCHAR_TYPE: *(unsigned char*)(lvalue) = (unsigned char)value; break;
case SHORT_TYPE: *(short*)(lvalue) = (short)value; break;
case USHORT_TYPE: *(unsigned short*)(lvalue) = (unsigned short)value; break;
case LONG_TYPE: *(long*)(lvalue) = (long)value; break;
case ULONG_TYPE: *(unsigned long*)(lvalue) = (unsigned long)value; break;
case VERTEX_TYPE:
case EDGE_TYPE:
case FACET_TYPE:
case BODY_TYPE:
case FACETEDGE_TYPE:
case ELEMENTID_TYPE: break;
default: *(int*)(lvalue) = (int)value; break;
}
if ( node->flags & RECALC_NODE )
recalc_flag = 1;
break;
}
case ARRAY_ASSIGNOP_VERTEX_NORMAL_:
{ MAT2D(normal,MAXCOORD,MAXCOORD);
REAL mag;
int normcount;
element_id id;
/* pop datastarts off stack */
REAL *q = *(REAL**)(stacktop--); /* not actually used, just pops stack */
REAL *p = *(REAL**)(stacktop--);
struct array *alvalue = get_name_arrayptr(node->op2.name_id,localstack,localbase);
int count = ( alvalue->datacount < SDIM ) ? alvalue->datacount : SDIM;
if ( node[node->right].op1.localnum )
id = *(element_id*)get_localp(node[node->right].op1.localnum);
else id = q_id;
normcount = new_calc_vertex_normal(id,normal);
project_vertex_normals(id,normal,normcount);
mag = sqrt(SDIM_dot(normal[0],normal[0]));
if ( mag == 0.0 ) mag = 1;
switch ( node->op1.assigntype )
{ case ASSIGN_:
for ( i = 0 ; i < count ; i++ )
p[i] = normal[0][i]/mag;
break;
case PLUSASSIGN_:
for ( i = 0 ; i < count ; i++ )
p[i] += normal[0][i]/mag;
break;
case SUBASSIGN_:
for ( i = 0 ; i < count ; i++ )
p[i] -= normal[0][i]/mag;
break;
case MULTASSIGN_:
for ( i = 0 ; i < count ; i++ )
p[i] *= normal[0][i]/mag;
break;
case DIVASSIGN_:
for ( i = 0 ; i < count ; i++ )
p[i] /= normal[0][i]/mag;
break;
}
break;
}
case ARRAY_ASSIGNOP_EDGE_VECTOR_:
{ /* pop datastarts off stack */
element_id id;
REAL *q = *(REAL**)(stacktop--); /* not actually used, just pops stack */
REAL *p = *(REAL**)(stacktop--);
REAL v[MAXCOORD];
struct array *alvalue = get_name_arrayptr(node->op2.name_id,localstack,localbase);
int count = ( alvalue->datacount < SDIM ) ? alvalue->datacount : SDIM;
if ( node[node->right].op1.localnum )
id = *(element_id*)get_localp(node[node->right].op1.localnum);
else id = q_id;
get_edge_side(id,v);
switch ( node->op1.assigntype )
{ case ASSIGN_:
for ( i = 0 ; i < count ; i++ )
p[i] = v[i];
break;
case PLUSASSIGN_:
for ( i = 0 ; i < count ; i++ )
p[i] += v[i];
break;
case SUBASSIGN_:
for ( i = 0 ; i < count ; i++ )
p[i] -= v[i];
break;
case MULTASSIGN_:
for ( i = 0 ; i < count ; i++ )
p[i] *= v[i];
break;
case DIVASSIGN_:
for ( i = 0 ; i < count ; i++ )
p[i] /= v[i];
break;
}
break;
}
case ARRAY_ASSIGNOP_FACET_NORMAL_:
{ /* pop datastarts off stack */
element_id id;
REAL *q = *((REAL**)stacktop--); /* not actually used, just pops stack */
REAL *p = *(REAL**)(stacktop--);
struct array *alvalue = get_name_arrayptr(node->op2.name_id,localstack,localbase);
int count = ( alvalue->datacount < SDIM ) ? alvalue->datacount : SDIM;
REAL v[MAXCOORD];
if ( node[node->right].op1.localnum )
id = *(element_id*)get_localp(node[node->right].op1.localnum);
else id = q_id;
get_facet_normal(id,v);
switch ( node->op1.assigntype )
{ case ASSIGN_:
for ( i = 0 ; i < count ; i++ )
p[i] = v[i];
break;
case PLUSASSIGN_:
for ( i = 0 ; i < count ; i++ )
p[i] += v[i];
break;
case SUBASSIGN_:
for ( i = 0 ; i < count ; i++ )
p[i] -= v[i];
break;
case MULTASSIGN_:
for ( i = 0 ; i < count ; i++ )
p[i] *= v[i];
break;
case DIVASSIGN_:
for ( i = 0 ; i < count ; i++ )
p[i] /= v[i];
break;
}
break;
}
case ARRAY_ASSIGNOP_ARRAY_:
{
struct array *alvalue= get_name_arrayptr(node->op2.name_id,localstack,localbase);
struct array *arvalue = get_name_arrayptr(node->op3.name_id,localstack,localbase);
int inx[100]; /* keep track of indices */
char *p,*q;
int j,k;
char *pspots[100],*qspots[100];
int pstride[100],qstride[100];
int minsize[100],lastsize;
/* Was checked in parser that the arrays have the same number
of indices, but might be different sizes. So do
intersection. */
/* pop datastarts off stack */
q = *(char**)(stacktop--);
p = *(char**)(stacktop--);
for ( i = 0 ; i < arvalue->dim ; i++ )
{ inx[i] = 0;
minsize[i] = arvalue->sizes[i] < alvalue->sizes[i] ?
arvalue->sizes[i] : alvalue->sizes[i] ;
pspots[i] = p;
qspots[i] = q;
}
if ( alvalue->dim >= 2 )
{
pstride[alvalue->dim-2] = alvalue->sizes[alvalue->dim-1]*alvalue->itemsize;
qstride[arvalue->dim-2] = arvalue->sizes[arvalue->dim-1]*arvalue->itemsize;
for ( i = arvalue->dim - 3 ; i >= 0 ; i-- )
{ pstride[i] = pstride[i+1]*alvalue->sizes[i+1];
qstride[i] = qstride[i+1]*arvalue->sizes[i+1];
}
}
lastsize = minsize[arvalue->dim-1];
do
{ /* do a row */
switch ( arvalue->datatype )
{ case REAL_TYPE:
{ REAL *pp = (REAL*)p;
REAL *qq = (REAL*)q;
switch ( node->op1.assigntype )
{ case ASSIGN_:
for ( i = 0 ; i < lastsize ; i++ )
*(pp++) = *(qq++);
break;
case PLUSASSIGN_:
for ( i = 0 ; i < lastsize ; i++ )
*(pp++) += *(qq++);
break;
case SUBASSIGN_:
for ( i = 0 ; i < lastsize ; i++ )
*(pp++) -= *(qq++);
break;
case MULTASSIGN_:
for ( i = 0 ; i < lastsize ; i++ )
*(pp++) *= *(qq++);
break;
case DIVASSIGN_:
for ( i = 0 ; i < lastsize ; i++ )
*(pp++) /= *(qq++);
break;
}
}
break; /* end REAL_TYPE */
case INTEGER_TYPE:
{ int *pp = (int*)p;
int *qq = (int*)q;
switch ( node->op1.assigntype )
{ case ASSIGN_:
for ( i = 0 ; i < lastsize ; i++ )
*(pp++) = *(qq++);
break;
case PLUSASSIGN_:
for ( i = 0 ; i < lastsize ; i++ )
*(pp++) += *(qq++);
break;
case SUBASSIGN_:
for ( i = 0 ; i < lastsize ; i++ )
*(pp++) -= *(qq++);
break;
case MULTASSIGN_:
for ( i = 0 ; i < lastsize ; i++ )
*(pp++) *= *(qq++);
break;
case DIVASSIGN_:
for ( i = 0 ; i < lastsize ; i++ )
*(pp++) /= *(qq++);
break;
}
break; /* end INTEGER_TYPE */
}
}
/* increment pointers */
for ( j = arvalue->dim-2 ; j >= 0 ; j-- )
{ pspots[j] += pstride[j];
qspots[j] += qstride[j];
if ( ++inx[j] < minsize[j] )
{ p = pspots[j];
q = qspots[j];
for ( k = j+1 ; k < alvalue->dim-1 ; k++ )
{ pspots[k] = p;
qspots[k] = q;
}
break;
}
inx[j] = 0 ;
}
} while ( j >= 0 );
if ( node->flags & RECALC_NODE )
recalc_flag = 1;
break;
} /* end ARRAY_ASSIGNOP_ARRAY_ */
case ARRAY_ASSIGNOP_SCALAR_:
{
struct array *alvalue= get_name_arrayptr(node->op2.name_id,localstack,localbase);
REAL scalar = *(stacktop--);
char *p = *(char**)(stacktop--);
int lastsize = alvalue->datacount;
switch ( alvalue->datatype )
{ case REAL_TYPE:
{ REAL *pp = (REAL*)p;
switch ( node->op1.assigntype )
{ case ASSIGN_:
for ( i = 0 ; i < lastsize ; i++ )
*(pp++) = scalar;
break;
case PLUSASSIGN_:
for ( i = 0 ; i < lastsize ; i++ )
*(pp++) += scalar;
break;
case SUBASSIGN_:
for ( i = 0 ; i < lastsize ; i++ )
*(pp++) -= scalar;
break;
case MULTASSIGN_:
for ( i = 0 ; i < lastsize ; i++ )
*(pp++) *= scalar;
break;
case DIVASSIGN_:
if ( scalar == 0.0 )
{
sprintf(errmsg,"Division by zero.\n");
sprintf(errmsg+strlen(errmsg),
"(source file %s, line %d)\n",
file_names[node->file_no],node->line_no);
kb_error(4677,errmsg,RECOVERABLE);
}
for ( i = 0 ; i < lastsize ; i++ )
*(pp++) /= scalar;
break;
}
break; /* end REAL_TYPE */
}
case INTEGER_TYPE:
{ int intscalar = (int)floor(scalar);
int *pp = (int*)p;
switch ( node->op1.assigntype )
{ case ASSIGN_:
for ( i = 0 ; i < lastsize ; i++ )
*(pp++) = intscalar;
break;
case PLUSASSIGN_:
for ( i = 0 ; i < lastsize ; i++ )
*(pp++) += intscalar;
break;
case SUBASSIGN_:
for ( i = 0 ; i < lastsize ; i++ )
*(pp++) -= intscalar;
break;
case MULTASSIGN_:
for ( i = 0 ; i < lastsize ; i++ )
*(pp++) = (int)(floor(*(int*)p) * scalar);
break;
case DIVASSIGN_:
if ( scalar == 0.0 )
kb_error(4678,"Division by zero.\n",RECOVERABLE);
for ( i = 0 ; i < lastsize ; i++ )
*(pp++) /= (int)floor((*(int*)p) / scalar);
break;
}
}
break; /* end INTEGER_TYPE */
}
if ( node->flags & RECALC_NODE )
recalc_flag = 1;
} /* end ARRAY_ASSIGNOP_SCALAR */
break;
case ARRAY_ASSIGNOP_S_X_A_:
{ struct array *alvalue= get_name_arrayptr(node->op2.name_id,localstack,localbase);
struct array *arvalue= get_name_arrayptr(node->op3.name_id,localstack,localbase);
int inx[100]; /* keep track of indices */
char *p,*q;
int j,k;
char *pspots[100],*qspots[100];
int pstride[100],qstride[100];
int minsize[100],lastsize;
REAL scalar;
/* Was checked in parser that the arrays have the same number
of indices, but might be different sizes. So do
intersection. */
/* pop datastarts off stack */
q = *(char**)(stacktop--);
scalar = *(stacktop--);
p = *(char**)(stacktop--);
for ( i = 0 ; i < arvalue->dim ; i++ )
{ inx[i] = 0;
minsize[i] = arvalue->sizes[i] < alvalue->sizes[i] ?
arvalue->sizes[i] : alvalue->sizes[i] ;
pspots[i] = p;
qspots[i] = q;
}
if ( alvalue->dim >= 2 )
{
pstride[alvalue->dim-2] = alvalue->sizes[alvalue->dim-1]*alvalue->itemsize;
qstride[arvalue->dim-2] = arvalue->sizes[arvalue->dim-1]*arvalue->itemsize;
for ( i = arvalue->dim - 3 ; i >= 0 ; i-- )
{ pstride[i] = pstride[i+1]*alvalue->sizes[i+1];
qstride[i] = qstride[i+1]*arvalue->sizes[i+1];
}
}
lastsize = minsize[arvalue->dim-1];
p = pspots[0];
q = qspots[0];
do
{ /* do a row */
switch ( arvalue->datatype )
{ case REAL_TYPE:
{ REAL *pp = (REAL*)p;
REAL *qq = (REAL*)q;
switch ( node->op1.assigntype )
{ case ASSIGN_:
for ( i = 0 ; i < lastsize ; i++ )
*(pp++) = *(qq++)*scalar;
break;
case PLUSASSIGN_:
for ( i = 0 ; i < lastsize ; i++ )
*(pp++) += *(qq++)*scalar;
break;
case SUBASSIGN_:
for ( i = 0 ; i < lastsize ; i++ )
*(pp++) -= *(qq++)*scalar;
break;
case MULTASSIGN_:
for ( i = 0 ; i < lastsize ; i++ )
*(pp++) *= *(qq++)*scalar;
break;
case DIVASSIGN_:
for ( i = 0 ; i < lastsize ; i++ )
*(pp++) /= *(qq++)*scalar;
break;
}
break; /* end REAL_TYPE */
}
case INTEGER_TYPE:
{ int *pp = (int*)p;
int *qq = (int*)q;
switch ( node->op1.assigntype )
{ case ASSIGN_:
for ( i = 0 ; i < lastsize ; i++ )
*(pp++) = (int)floor(*(qq++)*scalar);
break;
case PLUSASSIGN_:
for ( i = 0 ; i < lastsize ; i++ )
*(pp++) += (int)floor(*(qq++)*scalar);
break;
case SUBASSIGN_:
for ( i = 0 ; i < lastsize ; i++ )
*(pp++) -= (int)floor(*(qq++)*scalar);
break;
case MULTASSIGN_:
for ( i = 0 ; i < lastsize ; i++ )
*(pp++) *= (int)floor(*(qq++)*scalar);
break;
case DIVASSIGN_:
if ( scalar == 0.0 )
kb_error(4679,"Division by zero.\n",RECOVERABLE);
for ( i = 0 ; i < lastsize ; i++ )
*(pp++) /= (int)floor(*(qq++)*scalar);
break;
}
break; /* end INTEGER_TYPE */
}
}
/* increment pointers */
for ( j = arvalue->dim-2 ; j >= 0 ; j-- )
{ pspots[j] += pstride[j];
qspots[j] += qstride[j];
if ( ++inx[j] < minsize[j] )
{ p = pspots[j];
q = qspots[j];
for ( k = j+1 ; k < alvalue->dim-1 ; k++ )
{ pspots[k] = p;
qspots[k] = q;
}
break;
}
inx[j] = 0 ;
}
} while ( j >= 0 );
if ( node->flags & RECALC_NODE )
recalc_flag = 1;
break;
} /* end ARRAY_ASSIGNOP_S_X_A_ */
case ARRAY_ASSIGNOP_A_P_A_:
{
struct array *alvalue= get_name_arrayptr(node->op2.name_id,localstack,localbase);
struct array *arvalue= get_name_arrayptr(node->op3.name_id,localstack,localbase);
struct array *asvalue= get_name_arrayptr(node->op4.name_id,localstack,localbase);
int inx[100]; /* keep track of indices */
char *p,*q,*s;
int j,k;
char *pspots[100],*qspots[100],*sspots[100];
int pstride[100],qstride[100],sstride[100];
int minsize[100],lastsize;
/* Was checked in parser that the arrays have the same number
of indices, but might be different sizes. So do
intersection. */
/* pop datastarts off stack */
s = *(char**)(stacktop--);
q = *(char**)(stacktop--);
p = *(char**)(stacktop--);
for ( i = 0 ; i < arvalue->dim ; i++ )
{ inx[i] = 0;
minsize[i] = arvalue->sizes[i] < alvalue->sizes[i] ?
arvalue->sizes[i] : alvalue->sizes[i] ;
if ( minsize[i] > asvalue->sizes[i] )
minsize[i] = asvalue->sizes[i];
pspots[i] = p;
qspots[i] = q;
sspots[i] = s;
}
if ( alvalue->dim >= 2 )
{
pstride[alvalue->dim-2] = alvalue->sizes[alvalue->dim-1]*alvalue->itemsize;
qstride[arvalue->dim-2] = arvalue->sizes[arvalue->dim-1]*arvalue->itemsize;
sstride[asvalue->dim-2] = asvalue->sizes[asvalue->dim-1]*asvalue->itemsize;
for ( i = arvalue->dim - 3 ; i >= 0 ; i-- )
{ pstride[i] = pstride[i+1]*alvalue->sizes[i+1];
qstride[i] = qstride[i+1]*arvalue->sizes[i+1];
sstride[i] = sstride[i+1]*asvalue->sizes[i+1];
}
}
lastsize = minsize[arvalue->dim-1];
p = pspots[0];
q = qspots[0];
s = sspots[0];
do
{ /* do a row */
switch ( arvalue->datatype )
{ case REAL_TYPE:
{ REAL *pp = (REAL*)p;
REAL *qq = (REAL*)q;
REAL *ss = (REAL*)s;
switch ( node->op1.assigntype )
{ case ASSIGN_:
for ( i = 0 ; i < lastsize ; i++ )
*(pp++) = *(qq++) + *(ss++);
break;
case PLUSASSIGN_:
for ( i = 0 ; i < lastsize ; i++ )
*(pp++) += *(qq++) + *(ss++);
break;
case SUBASSIGN_:
for ( i = 0 ; i < lastsize ; i++ )
*(pp++) -= *(qq++) + *(ss++);
break;
case MULTASSIGN_:
for ( i = 0 ; i < lastsize ; i++ )
*(pp++) *= *(qq++) + *(ss++);
break;
case DIVASSIGN_:
for ( i = 0 ; i < lastsize ; i++ )
*(pp++) /= *(qq++) + *(ss++);
break;
}
break; /* end REAL_TYPE */
}
case INTEGER_TYPE:
{ int *pp = (int*)p;
int *qq = (int*)q;
int *ss = (int*)s;
switch ( node->op1.assigntype )
{ case ASSIGN_:
for ( i = 0 ; i < lastsize ; i++ )
*(pp++) = *(qq++) + *(ss++);
break;
case PLUSASSIGN_:
for ( i = 0 ; i < lastsize ; i++ )
*(pp++) += *(qq++) + *(ss++);
break;
case SUBASSIGN_:
for ( i = 0 ; i < lastsize ; i++ )
*(pp++) -= *(qq++) + *(ss++);
break;
case MULTASSIGN_:
for ( i = 0 ; i < lastsize ; i++ )
*(pp++) *= *(qq++) + *(ss++);
break;
case DIVASSIGN_:
for ( i = 0 ; i < lastsize ; i++ )
*(pp++) /= *(qq++) + *(ss++);
break;
}
break; /* end INTEGER_TYPE */
}
}
/* increment pointers */
for ( j = arvalue->dim-2 ; j >= 0 ; j-- )
{ pspots[j] += pstride[j];
qspots[j] += qstride[j];
sspots[j] += sstride[j];
if ( ++inx[j] < minsize[j] )
{ p = pspots[j];
q = qspots[j];
s = sspots[j];
for ( k = j+1 ; k < alvalue->dim-1 ; k++ )
{ pspots[k] = p;
qspots[k] = q;
sspots[k] = s;
}
break;
}
inx[j] = 0 ;
}
} while ( j >= 0 );
if ( node->flags & RECALC_NODE )
recalc_flag = 1;
} /* end ARRAY_ASSIGNOP_A_P_A_ */
break;
case ARRAY_ASSIGNOP_A_S_A_:
{
struct array *alvalue= get_name_arrayptr(node->op2.name_id,localstack,localbase);
struct array *arvalue= get_name_arrayptr(node->op3.name_id,localstack,localbase);
struct array *asvalue= get_name_arrayptr(node->op4.name_id,localstack,localbase);
int inx[100]; /* keep track of indices */
char *p,*q,*s;
int j,k;
char *pspots[100],*qspots[100],*sspots[100];
int pstride[100],qstride[100],sstride[100];
int minsize[100],lastsize;
/* Was checked in parser that the arrays have the same number
of indices, but might be different sizes. So do
intersection. */
/* pop datastarts off stack */
s = *(char**)(stacktop--);
q = *(char**)(stacktop--);
p = *(char**)(stacktop--);
for ( i = 0 ; i < arvalue->dim ; i++ )
{ inx[i] = 0;
minsize[i] = arvalue->sizes[i] < alvalue->sizes[i] ?
arvalue->sizes[i] : alvalue->sizes[i] ;
if ( minsize[i] > asvalue->sizes[i] )
minsize[i] = asvalue->sizes[i];
pspots[i] = p;
qspots[i] = q;
sspots[i] = s;
}
if ( alvalue->dim >= 2 )
{
pstride[alvalue->dim-2] = alvalue->sizes[alvalue->dim-1]*alvalue->itemsize;
qstride[arvalue->dim-2] = arvalue->sizes[arvalue->dim-1]*arvalue->itemsize;
sstride[asvalue->dim-2] = asvalue->sizes[asvalue->dim-1]*asvalue->itemsize;
for ( i = arvalue->dim - 3 ; i >= 0 ; i-- )
{ pstride[i] = pstride[i+1]*alvalue->sizes[i+1];
qstride[i] = qstride[i+1]*arvalue->sizes[i+1];
sstride[i] = sstride[i+1]*asvalue->sizes[i+1];
}
}
lastsize = minsize[arvalue->dim-1];
p = pspots[0];
q = qspots[0];
s = sspots[0];
do
{ /* do a row */
switch ( arvalue->datatype )
{ case REAL_TYPE:
{ REAL *pp = (REAL*)p;
REAL *qq = (REAL*)q;
REAL *ss = (REAL*)s;
switch ( node->op1.assigntype )
{ case ASSIGN_:
for ( i = 0 ; i < lastsize ; i++ )
*(pp++) = *(qq++) - *(ss++);
break;
case PLUSASSIGN_:
for ( i = 0 ; i < lastsize ; i++ )
*(pp++) += *(qq++) - *(ss++);
break;
case SUBASSIGN_:
for ( i = 0 ; i < lastsize ; i++ )
*(pp++) -= *(qq++) - *(ss++);
break;
case MULTASSIGN_:
for ( i = 0 ; i < lastsize ; i++ )
*(pp++) *= *(qq++) - *(ss++);
break;
case DIVASSIGN_:
for ( i = 0 ; i < lastsize ; i++ )
*(pp++) /= *(qq++) - *(ss++);
break;
}
break; /* end REAL_TYPE */
}
case INTEGER_TYPE:
{ int *pp = (int*)p;
int *qq = (int*)q;
int *ss = (int*)s;
switch ( node->op1.assigntype )
{ case ASSIGN_:
for ( i = 0 ; i < lastsize ; i++ )
*(pp++) = *(qq++) - *(ss++);
break;
case PLUSASSIGN_:
for ( i = 0 ; i < lastsize ; i++ )
*(pp++) += *(qq++) - *(ss++);
break;
case SUBASSIGN_:
for ( i = 0 ; i < lastsize ; i++ )
*(pp++) -= *(qq++) - *(ss++);
break;
case MULTASSIGN_:
for ( i = 0 ; i < lastsize ; i++ )
*(pp++) *= *(qq++) - *(ss++);
break;
case DIVASSIGN_:
for ( i = 0 ; i < lastsize ; i++ )
*(pp++) /= *(qq++) - *(ss++);
break;
}
break; /* end INTEGER_TYPE */
}
}
/* increment pointers */
for ( j = arvalue->dim-2 ; j >= 0 ; j-- )
{ pspots[j] += pstride[j];
qspots[j] += qstride[j];
sspots[j] += sstride[j];
if ( ++inx[j] < minsize[j] )
{ p = pspots[j];
q = qspots[j];
s = sspots[j];
for ( k = j+1 ; k < alvalue->dim-1 ; k++ )
{ pspots[k] = p;
qspots[k] = q;
sspots[k] = s;
}
break;
}
inx[j] = 0 ;
}
} while ( j >= 0 );
if ( node->flags & RECALC_NODE )
recalc_flag = 1;
}
break; /* end ARRAY_ASSIGNOP_A_S_A_ */
case PLUSASSIGN_:
case SUBASSIGN_:
case MULTASSIGN_:
case DIVASSIGN_:
case SET_GLOBAL_:
{ struct global *g = globals(node->op1.name_id);
REAL *x;
if ( g->flags & GLOB_LOCALVAR )
x = localstack + g->value.offset;
else if ( g->flags & ORDINARY_PARAM )
x = &g->value.real;
else
{ sprintf(errmsg, "Variable %s is read-only.\n",g->name);
sprintf(errmsg+strlen(errmsg),"(source file %s, line %d)\n",
file_names[node->file_no],node->line_no);
kb_error(3455,errmsg,WARNING);
break;
}
if ( g->flags & STRINGVAL )
{ if ( g->flags & GLOB_LOCALVAR )
myfree(*(char**)x);
else myfree(g->value.string);
g->flags &= ~STRINGVAL;
}
switch(node->type)
{
case SET_GLOBAL_: *x = *(stacktop--); break;
case PLUSASSIGN_: *x += *(stacktop--); break;
case SUBASSIGN_: *x -= *(stacktop--); break;
case MULTASSIGN_: *x *= *(stacktop--); break;
case DIVASSIGN_:
if ( *stacktop == 0.0 )
{ sprintf(errmsg,"Division by zero.\n");
sprintf(errmsg+strlen(errmsg),"(source file %s, line %d)\n",
file_names[node->file_no],node->line_no);
kb_error(2562,errmsg,RECOVERABLE);
}
*x /= *(stacktop--); break;
}
if ( g->flags & RECALC_PARAMETER )
recalc_flag = 1;
}
break;
case SET_PERM_GLOBAL_:
{ struct global *g = perm_globals(node->op1.name_id);
REAL *x;
if ( g->flags & STRINGVAL )
{ free(g->value.string); g->flags &= ~STRINGVAL; }
x = &g->value.real;
*x = *(stacktop--);
if ( g->flags & RECALC_PARAMETER )
recalc_flag = 1;
}
break;
/* end whole-array syntax */
case FINISHED:
if ( this_frame->flags & BASE_OF_EVAL )
{ /* want to exit from eval() */
goto the_exit;
}
else /* want to return within eval() */
{
if ( localbase && (localbase->flags & LL_HAS_ARRAY) )
{ /* de-allocate local array storage */
int n;
for ( n = 0 ; n < localbase->count ; n++ )
{ struct global *g = &(localbase->list[n].g);
if ( g->flags & ARRAY_PARAM )
{ struct array *a = *(struct array**)(newstack + g->value.offset);
if ( a ) temp_free((char*)a);
a = NULL;
}
}
}
return_value = *stacktop;
stacktop = (REAL*)this_frame;
stacktop--; /* since points to occupied spot */
node = this_frame->return_node;
td->frame_spot = this_frame->parent_frame_spot;
localstack = (REAL*)(this_frame+1);
PROF_EVAL_END(ex);
ex = this_frame->base_ex;
PROF_EVAL_START(ex);
localbase = ex->locals;
if ( ex->locals )
localcount = ex->locals->totalsize;
else localcount = 0;
}
break;
default:
other_stuff(node,&recalc_flag,
&update_display_flag,q_id,localstack,localbase);
break;
}
if ( breakflag )
{ switch ( breakflag )
{ case BREAKFULL:
{ sprintf(errmsg,"Command aborted due to user interrupt.\n");
sprintf(errmsg+strlen(errmsg),"(source file %s, line %d)\n",
file_names[node->file_no],node->line_no);
kb_error(2073,errmsg, RECOVERABLE);
}
break;
case BREAKABORT:
{ sprintf(errmsg,"Command aborted.\n");
sprintf(errmsg+strlen(errmsg),"(source file %s, line %d)\n",
file_names[node->file_no],node->line_no);
kb_error(3234,errmsg, RECOVERABLE_ABORT);
}
break;
case BREAKAFTERWARNING:
{ sprintf(errmsg,"Command aborted due to break_after_warning.\n");
kb_error(3109,errmsg, RECOVERABLE);
}
}
}
#ifdef _XXDEBUG
{ static int didwarn;
/* Check predicted stack alignment. There are circumstances when alignment
is not equal (e.g. skipping procedure bodies when assigning them,
so just check there is room. */
if ( (node[1].type != SETUP_FRAME_) &&
(stacktop > (REAL*)this_frame + FRAME_SPACE + localcount + node->stack_spot) )
{ sprintf(errmsg,"Intermediate stack misalignment after node type %d.\n",
node->type);
sprintf(errmsg+strlen(errmsg),"(source file %s, line %d)\n",
file_names[node->file_no],node->line_no);
if ( ! didwarn ) /* to prevent error cascade */
kb_error(2671,errmsg,WARNING);
didwarn = 1;
}
else didwarn = 0;
}
#endif
if ( td->stack_top < td->eval_stack )
kb_error(5243,"BAD EVAL STACK\n",RECOVERABLE);
if ( newstack[stackmax-1] != STACKMAGIC ) /* nearing overflow, so extend */
{ kb_error(3488,"Evaluation stack overflow.\n",RECOVERABLE);
}
}
the_exit:
if ( !params )
{ if ( web.counts_changed )
flush_counts();
if ( recalc_flag && autorecalc_flag ) recalc();
else if ( update_display_flag ) update_display();
}
PROF_EVAL_END(ex);
iterate_flag = old_flag;
if ( stacktop == (REAL*)this_frame + FRAME_SPACE + localcount )
{ /* Have return value on stack */
REAL retval = *(stacktop--);
stacktop = (REAL*)this_frame;
stacktop--; /* since points to occupied spot */
td->frame_spot = this_frame->parent_frame_spot;
return retval;
}
else if ( stacktop != (REAL*)this_frame + FRAME_SPACE + localcount - 1)
{
sprintf(errmsg,"Internal error: Stack misalignment by %d in eval()\n",
stacktop-(REAL*)this_frame-localcount-FRAME_SPACE+1);
sprintf(errmsg+strlen(errmsg),"(source file %s, line %d)\n",
file_names[node->file_no],node->line_no);
kb_error(1298,errmsg, RECOVERABLE);
}
stacktop = (REAL*)this_frame;
stacktop--; /* since points to occupied spot */
td->frame_spot = this_frame->parent_frame_spot;
return 0.0;
} /* end eval() */
/************************************************************************
*
* function: flush_counts()
*
* purpose: print pending counts
*/
void flush_counts()
{
if ( web.counts_changed & fix_count_bit )
{ sprintf(msg,"Fixed: %d\n",web.fix_count); outstring(msg); }
if ( web.counts_changed & unfix_count_bit )
{ sprintf(msg,"Unfixed: %d\n",web.unfix_count); outstring(msg); }
if ( web.counts_changed & equi_count_bit )
{ sprintf(msg,"Edges equiangulated: %d\n",web.equi_count); outstring(msg); }
if ( web.counts_changed & edge_delete_count_bit )
{ sprintf(msg,"Edges deleted: %d\n",web.edge_delete_count); outstring(msg); }
if ( web.counts_changed & facet_delete_count_bit )
{ sprintf(msg,"Facets deleted: %d\n",web.facet_delete_count); outstring(msg); }
if ( web.counts_changed & edge_refine_count_bit )
{ sprintf(msg,"Edges refined: %d\n",web.edge_refine_count); outstring(msg); }
if ( web.counts_changed & facet_refine_count_bit )
{ sprintf(msg,"Facets refined: %d\n",web.facet_refine_count); outstring(msg); }
if ( web.counts_changed & vertex_dissolve_count_bit )
{ sprintf(msg,"Vertices dissolved: %d\n",web.vertex_dissolve_count); outstring(msg); }
if ( web.counts_changed & edge_dissolve_count_bit )
{ sprintf(msg, "Edges dissolved: %d\n",web.edge_dissolve_count); outstring(msg); }
if ( web.counts_changed & facet_dissolve_count_bit )
{ sprintf(msg,"Facets dissolved: %d\n",web.facet_dissolve_count); outstring(msg); }
if ( web.counts_changed & body_dissolve_count_bit )
{ sprintf(msg,"Bodies dissolved: %d\n",web.body_dissolve_count); outstring(msg); }
if ( web.counts_changed & edge_reverse_count_bit )
{ sprintf(msg, "Edges reversed: %d\n",web.edge_reverse_count); outstring(msg); }
if ( web.counts_changed & facet_reverse_count_bit )
{ sprintf(msg, "Facets reversed: %d\n",web.facet_reverse_count); outstring(msg); }
if ( web.counts_changed & vertex_pop_count_bit )
{ sprintf(msg,"Vertices popped: %d\n",web.vertex_pop_count); outstring(msg); }
if ( web.counts_changed & edge_pop_count_bit )
{ sprintf(msg,"Edges popped: %d\n",web.edge_pop_count); outstring(msg); }
if ( web.counts_changed & pop_tri_to_edge_count_bit )
{ sprintf(msg,"pop_tri_to_edge count: %d\n",web.pop_tri_to_edge_count); outstring(msg); }
if ( web.counts_changed & pop_edge_to_tri_count_bit )
{ sprintf(msg,"pop_edge_to_tri count: %d\n",web.pop_edge_to_tri_count); outstring(msg); }
if ( web.counts_changed & pop_quad_to_quad_count_bit )
{ sprintf(msg,"pop_quad_to_quad count: %d\n",web.pop_quad_to_quad_count); outstring(msg); }
if ( web.counts_changed & edgeswap_count_bit )
{ sprintf(msg,"Edges swapped: %d\n",web.edgeswap_count); outstring(msg); }
if ( web.counts_changed & t1_edgeswap_count_bit )
{ sprintf(msg,"T1 swaps: %d\n",web.t1_edgeswap_count); outstring(msg); }
web.counts_reported = ~0;
web.counts_changed = 0;
}
/************************************************************************
*
* function: reset_counts()
*
* purpose: set counts to 0 for event counts and profiling counts.
*/
void reset_counts()
{
web.equi_count = 0;
web.edge_delete_count = 0;
web.facet_delete_count = 0;
web.edge_refine_count = 0;
web.facet_refine_count = 0;
web.notch_count = 0;
web.vertex_dissolve_count = 0;
web.edge_dissolve_count = 0;
web.facet_dissolve_count = 0;
web.body_dissolve_count = 0;
web.edge_reverse_count = 0;
web.facet_reverse_count = 0;
web.vertex_pop_count = 0;
web.edge_pop_count = 0;
web.pop_tri_to_edge_count = 0;
web.pop_edge_to_tri_count = 0;
web.pop_quad_to_quad_count = 0;
web.where_count = 0;
web.edgeswap_count = 0;
web.fix_count = 0;
web.unfix_count = 0;
web.t1_edgeswap_count = 0;
web.notch_count = 0;
web.counts_reported = 0;
web.counts_changed = 0;
#ifdef PROFILING_ENABLED
{ int i;
for ( i = LOW_INST ; i < meth_inst_count ; i++ )
{ struct method_instance *mi = METH_INSTANCE(i);
mi->value_call_count = mi->grad_call_count = mi->hess_call_count = 0;
mi->value_elapsed_time = mi->grad_elapsed_time
= mi->hess_elapsed_time = 0.0;
}
for ( i = 0 ; i < 2 ; i++ )
{ element_setup_elapsed_time[i] = 0;
calc_quants_elapsed_time[i] = 0;
calc_quant_grads_elapsed_time[i] = 0;
calc_quant_hess_elapsed_time[i] = 0;
exparse_elapsed_time[i] = 0;
yyparse_elapsed_time[i] = 0;
yylex_elapsed_time[i] = 0;
kblex_elapsed_time[i] = 0;
hessian_solve_elapsed_time[i] = 0;
hessian_mul_elapsed_time[i] = 0;
hessian_AIJ_setup_elapsed_time[i] = 0;
hessian_constraint_setup_elapsed_time[i] = 0;
hessian_project_setup_elapsed_time[i] = 0;
hessian_factor_elapsed_time[i] = 0;
hessian_CHinvC_elapsed_time[i] = 0;
}
find_cpu_speed();
}
#endif
}
evolver-2.30c.dfsg/src/exprint.c 0000644 0001753 0001753 00000273671 11410765113 017072 0 ustar hazelsct hazelsct /*************************************************************
* This file is part of the Surface Evolver source code. *
* Programmer: Ken Brakke, brakke@susqu.edu *
*************************************************************/
/*****************************************************************
*
* File: exprint.c
*
* Purpose: To print user commands and functions in algebraic form
*
*/
#include "include.h"
#include "lex.h"
#include "ytab.h"
void check_room_left ARGS((size_t));
void print_quote ARGS((char*));
void linebreak ARGS((void));
void newline ARGS((void));
struct locallist_t *current_proc_locals[100];
int current_proc_depth;
char * assign_symbol ARGS((int));
char * assign_symbol (sym)
int sym;
{ switch ( sym )
{ case ASSIGN_: return ":=";
case PLUSASSIGN_: return "+=";
case SUBASSIGN_: return "-=";
case MULTASSIGN_: return "*=";
case DIVASSIGN_: return "/=";
}
return "";
}
/*****************************************************************
*
* Function print_express()
*
* Purpose: print expression in algebraic format
* Uses private working space, expanding as needed.
* Returns pointer to working space.
*
*/
static char *pos; /* current position in string */
static char vch;
static size_t strsize;
static char *strstart;
static char *linestart;
static int bracket_depth;
/* precedence levels for knowing how to parenthesize */
#define PREC_POW 50
#define PREC_UMINUS 45
#define PREC_MUL 40
#define PREC_DIV 40
#define PREC_ADD 35
#define PREC_SUB 35
#define PREC_COMP 30
#define PREC_NOT 25
#define PREC_AND 20
#define PREC_OR 15
#define PREC_COND 13
#define PREC_ASSIGN 10
#define PREC_ARG 0
/**************************************************************************
*
* Function: print_express()
*
* Purpose: Convert parse tree for expression to ASCII string in
* character array pos.
*/
char *print_express(node,c)
struct expnode *node; /* expression tree */
int c; /* character for parameters */
{
if ( !strstart ) /* for first time thru */
{ strsize = 200;
strstart = my_list_calloc(1,strsize,ETERNAL_BLOCK);
}
else strstart[0] = '\0';
linestart = pos = strstart;
vch = (char)c;
if ( !node || !node->root ) { strcpy(strstart,"{}"); return strstart;}
bracket_depth = 0;
current_proc_locals[0] = node->locals;
current_proc_depth = 0;
exprint_recur(node->root,0);
return strstart;
}
/**********************************************************************
*
* Function: linebreak()
*
* Purpose: Insert a linebreak when the line gets too long.
*/
#define INDENT 2
#define GOODLEN 75
#define MINLEN 30
void linebreak()
{ int i;
char *c,*cc;
char *minline = linestart + MINLEN;
int extra_indent = 0;
if ( pos - linestart < GOODLEN ) return;
cc = NULL;
/* search for end of quote, starting at end so don't break quote */
for ( c = pos-1 ; c != linestart ; c-- )
if ( *c == '"' ) { cc = (c[1] == ';') ? c+1 : c; break; }
if ( cc == NULL ) /* search for end bracket */
for ( c = linestart + GOODLEN ; c != minline ; c-- )
if ( *c == '}' ) { cc = (c[1] == ';') ? c+1 : c; break; }
if ( cc == NULL ) /* scan back for handy ';' */
for ( c = linestart + GOODLEN ; c != minline ; c-- )
if ( *c == ';' ) { cc = c; break; }
if ( cc == NULL ) /* just look for { */
for ( c = linestart + GOODLEN ; c != minline ; c-- )
if ( *c == '{' ) { cc = c; break; }
if ( cc == NULL ) extra_indent = 2;
if ( cc == NULL ) /* just look for space */
for ( c = linestart + GOODLEN ; c != minline ; c-- )
if ( *c == ' ' ) { cc = c; break; }
if ( cc == NULL ) /* just look for comma */
for ( c = linestart + GOODLEN ; c != minline ; c-- )
if ( *c == ',' ) { cc = c; break; }
if ( cc == NULL ) /* just look for = */
for ( c = linestart + GOODLEN ; c != minline ; c-- )
if ( *c == '=' ) { cc = c; break; }
if ( cc == NULL ) /* just look for logic signs */
for ( c = linestart + GOODLEN ; c != minline ; c-- )
if ( (*c == '&') || (*c == '%') )
{ cc = c; break; }
if ( cc == NULL ) /* just look for arithmetic signs */
for ( c = linestart + GOODLEN ; c != minline ; c-- )
if ( ((*c == '+') || (*c == '-')) && !(isalpha(c[-1]) && !isalpha(c[-2])))
{ cc = c; break; } /* don't split scientific notation */
if ( (cc == NULL) || (cc - linestart < GOODLEN/2) )
for ( c = linestart + GOODLEN ; c != minline ; c-- )
if ( ((*c == '*') || (*c == '/')) && (c[1] != '=') && (c[1] != '*') )
{ cc = c; break; }
if ( cc == NULL ) /* just look for closing parenthesis */
for ( c = linestart + GOODLEN ; c != minline ; c-- )
if ( *c == ')' ) { cc = c; break; }
if ( cc == NULL ) /* just look for opening parenthesis */
for ( c = linestart + GOODLEN ; c != minline ; c-- )
if ( *c == '(' ) { cc = c; break; }
/* Have break, so do split, with *cc as last character on old line */
if ( cc )
{ char *ch;
int bd = bracket_depth;
linestart = cc+3;
c = cc+1 ; while (*c == ' ' ) c++ ; /* skip spaces */
for ( ch = c ; ch < pos ; ch++ ) /* unwind bracket depth */
if ( *ch == '{' ) bd--;
else if ( *ch == '}' ) bd++;
pos = cc + 3 + INDENT*bd + extra_indent + strlen(c);
kb_memmove(cc+3+INDENT*bd+extra_indent,c,strlen(c));
cc[1] = (char)(bd ? ' ' : '\\');
cc[2] = '\n';
for ( i = 0 ; i < INDENT*bd + extra_indent ; i++ ) cc[i+3] = ' ';
*pos = 0;
}
else
{ if ( bracket_depth <= 0 ) *(pos++) = '\\';
*(pos++) = '\n';
linestart = pos;
for ( i = 0 ; i < INDENT*bracket_depth ; i++ ) *(pos++) = ' ';
*pos = 0;
}
}
/***************************************************************************
*
* function: newline()
*
* purpose: Begin a new line, suitably indented.
*/
void newline()
{
int i;
*(pos++) = '\n';
for ( i = 0 ; i < INDENT*bracket_depth ; i++ )
*(pos++) = ' ';
*pos = 0;
linestart = pos;
}
/**********************************************************************
*
* Function: check_room_left()
*
* Purpose: Keep print string from overflowing.
*/
void check_room_left(n)
size_t n; /* room needed */
{
/* check room remaining */
if ( (pos + n - strstart) > (int)strsize )
{ size_t len = pos - strstart;
size_t linespot = linestart - strstart;
strstart = my_list_realloc(strstart,strsize + 1000 + n,ETERNAL_BLOCK);
strsize += 1000 + n;
linestart = strstart + linespot;
pos = strstart + len;
}
}
void print_quote(c)
char *c;
{ check_room_left(strlen(c)+30);
convert_string(c,pos);
pos += strlen(pos);
}
/********************************************************************
*
* function: convert_string()
*
* purpose: convert string from internal to printable representation.
* Converts to C escapes, encloses in quotes.
*/
void convert_string(c,p)
char *c; /* source */
char *p; /* destination */
{
/* convert to C escape sequences */
*(p++) = '"';
if ( c )
for ( ; *c ; c++ )
switch ( *c )
{ case '\n': *(p++) = '\\'; *(p++) = 'n'; break;
case '\r': *(p++) = '\\'; *(p++) = 'r'; break;
case '\t': *(p++) = '\\'; *(p++) = 't'; break;
case '\b': *(p++) = '\\'; *(p++) = 'b'; break;
case '"': *(p++) = '\\'; *(p++) = 'q'; break;
case '\\': *(p++) = '\\'; *(p++) = '\\'; break;
default: *(p++) = *c;
}
*(p++) = '"';
*p = 0;
return;
}
/*************************************************************************
*
* function: exprint_recur()
*
* purpose: Convert node of parse tree to ASCII, recursively doing sons.
*/
void exprint_recur(node,prec_parent)
struct treenode *node;
int prec_parent; /* precedence level of parent, for parenthesizing */
{
struct treenode *nn;
struct extra *ex;
struct locallist_t *localbase = current_proc_locals[current_proc_depth];
check_room_left(1000);
/* insert some handy line breaks */
if ( (pos - linestart > GOODLEN) /* && (pos[-2] != ';') */ )
linebreak();
switch ( node->type )
{
case NOP_: return;
case NULLBLOCK_: sprintf(pos,"{}");pos+=2; return;
case NULLCMD_: return;
case BREAKPOINT_:
sprintf(pos,"breakpoint %s ",globals(node->op1.name_id)->name);
pos += strlen(pos);
exprint_recur(node+node->left,prec_parent);
return;
case UNSET_BREAKPOINT_:
if ( node->left )
{ sprintf(pos,"unset breakpoint %s ",globals(node->op1.name_id)->name);
pos += strlen(pos);
exprint_recur(node+node->left,prec_parent);
}
else
{ sprintf(pos,"unset breakpoints");
pos += strlen(pos);
}
return;
case SUPPRESS_WARNING_:
sprintf(pos,"suppress_warning "); pos += strlen(pos);
exprint_recur(node+node->left,prec_parent);
return;
case UNSUPPRESS_WARNING_:
sprintf(pos,"unsuppress_warning "); pos += strlen(pos);
exprint_recur(node+node->left,prec_parent);
return;
case KEYLOGFILE_:
sprintf(pos,"keylogfile "); pos += strlen(pos);
exprint_recur(node+node->left,prec_parent);
return;
case LOGFILE_:
sprintf(pos,"logfile "); pos += strlen(pos);
exprint_recur(node+node->left,prec_parent);
return;
case CMDLIST_:
exprint_recur(node+node->left,prec_parent);
if ( node->right )
{ sprintf(pos,"; "); pos += 2;
newline();
exprint_recur(node+node->right,prec_parent);
}
return;
case BACKQUOTE_START_: return;
case BACKQUOTE_END_:
exprint_recur(node+node->right,prec_parent); /* left was dummy */
return;
case TEXT_SPOT_:
exprint_recur(node+node->left,prec_parent);
*(pos++) = ',';
exprint_recur(node+node->right,prec_parent);
return;
case DISPLAY_TEXT_:
sprintf(pos,"display_text("); pos += strlen(pos);
exprint_recur(node+node->left,prec_parent);
*(pos++) = ',';
exprint_recur(node+node->right,prec_parent);
*(pos++) = ')';
return;
case DELETE_TEXT_:
sprintf(pos,"delete_text("); pos += strlen(pos);
exprint_recur(node+node->left,prec_parent);
*(pos++) = ')';
return;
case ACOMMANDEXPR_:
*(pos++) = '`'; /* surround with backquotes */
exprint_recur(node+node->left,prec_parent);
sprintf(pos,";`");
pos+=2; /* surround with backquotes; make sure of ; */
if ( node->right )
{ sprintf(pos,", "); pos += 2;
exprint_recur(node+node->right,prec_parent);
}
return;
case ATTR_FUNCTION_END_:
exprint_recur(node+node->left,prec_parent); /* define part */
strcat(pos," function {"); pos += strlen(pos);
exprint_recur(node+node->right,prec_parent); /* code part */
strcat(pos," } "); pos += strlen(pos);
return;
case ATTR_FUNCTION_:
exprint_recur(node+node->left,prec_parent); /* define part */
return;
case WRAP_VERTEX_:
strcat(pos,"wrap_vertex("); pos += strlen(pos);
exprint_recur(node+node->left,prec_parent);
sprintf(pos,","); pos++;
exprint_recur(node+node->right,prec_parent);
sprintf(pos,")"); pos++;
return;
case CREATE_VERTEX_:
sprintf(pos,"new_vertex("); pos += strlen(pos);
exprint_recur(node+node->left,prec_parent);
sprintf(pos,")"); pos++;
return;
case CREATE_EDGE_:
sprintf(pos,"new_edge("); pos += strlen(pos);
exprint_recur(node+node->left,prec_parent);
sprintf(pos,","); pos++;
exprint_recur(node+node->right,prec_parent);
sprintf(pos,")"); pos++;
return;
case CREATE_FACET_:
sprintf(pos,"new_facet("); pos += strlen(pos);
exprint_recur(node+node->left,prec_parent);
sprintf(pos,")"); pos++;
return;
case CREATE_BODY_:
sprintf(pos,"new_body"); pos += strlen(pos);
return;
case ELINDEX_:
exprint_recur(node+node->left,prec_parent);
if ( node->right )
{ *pos = '@'; pos++; *pos = 0;
exprint_recur(node+node->right,prec_parent);
}
return;
case PUSH_ELEMENT_ID_:
sprintf(pos,"%%sd@%d\n",(inverted(node->op1.id)?"-":""),
node->op1.id & OFFSETMASK, id_task(node->op1.id));
pos += strlen(pos);
return;
case VALID_ELEMENT_:
sprintf(pos,"valid_element(%s[",typenames[node->op1.eltype]);
pos += strlen(pos);
exprint_recur(node+node->left,prec_parent);
sprintf(pos,"])"); pos+=2;
return;
case VALID_CONSTRAINT_:
sprintf(pos,"valid_constraint(");
pos += strlen(pos);
exprint_recur(node+node->left,prec_parent);
sprintf(pos,")"); pos+=1;
return;
case VALID_BOUNDARY_:
sprintf(pos,"valid_boundary(");
pos += strlen(pos);
exprint_recur(node+node->left,prec_parent);
sprintf(pos,")"); pos+=1;
return;
case MATRIX_INVERSE_:
sprintf(pos,"matrix_inverse(%s,%s)",
globals(node->op1.name_id)->name,globals(node->op2.name_id)->name);
pos += strlen(pos);
return;
case MATRIX_MULTIPLY_:
sprintf(pos,"matrix_multiply(%s,%s,%s)",
globals(node->op1.name_id)->name,globals(node->op2.name_id)->name,
globals(node->op3.name_id)->name);
pos += strlen(pos);
return;
case MATRIX_DETERMINANT_:
sprintf(pos,"matrix_determinant(%s)",
globals(node->op1.name_id)->name);
pos += strlen(pos);
return;
case MERGE_VERTEX_:
sprintf(pos,"vertex_merge("); pos += strlen(pos);
exprint_recur(node+node->left,prec_parent);
sprintf(pos,","); pos++;
exprint_recur(node+node->right,prec_parent);
sprintf(pos,")"); pos++;
return;
case MERGE_EDGE_:
sprintf(pos,"edge_merge("); pos += strlen(pos);
exprint_recur(node+node->left,prec_parent);
sprintf(pos,","); pos++;
exprint_recur(node+node->right,prec_parent);
sprintf(pos,")"); pos++;
return;
case MERGE_FACET_:
sprintf(pos,"facet_merge("); pos += strlen(pos);
exprint_recur(node+node->left,prec_parent);
sprintf(pos,","); pos++;
exprint_recur(node+node->right,prec_parent);
sprintf(pos,")"); pos++;
return;
case COMMAND_BLOCK_:
sprintf(pos,"{ "); pos+=2; bracket_depth++;
exprint_recur(node+node->left,prec_parent);
bracket_depth--;
newline();
sprintf(pos,"}"); pos++;
return;
case LOCAL_LIST_START_:
sprintf (pos,"local ");
pos += strlen(pos);
exprint_recur(node+node->left,prec_parent);
break;
case DECLARE_LOCAL_:
{
if ( node->left )
{
exprint_recur(node+node->left,0);
*pos = ','; pos++;
}
sprintf (pos,"%s",globals(node->op1.name_id)->name);
pos += strlen(pos);
return;
}
case DEFINE_QUANTITY_:
{ struct gen_quant *g = GEN_QUANT(node->op1.quant_id);
sprintf(pos,"/* Definition of quantity %s was originally here.*/",
g->name);
pos += strlen(pos);
return;
}
case DEFINE_METHOD_INSTANCE_:
{ struct method_instance *mi = METH_INSTANCE(node->op1.meth_id);
sprintf(pos,
"/* Definition of method instance %s was originally here.*/",
mi->name);
pos += strlen(pos);
return;
}
case DEFINE_CONSTRAINT_:
{ struct constraint *con = get_constraint(node->op1.con_id);
if ( con->attr & NAMED_THING )
sprintf(pos,
"/* Definition of constraint %s was originally here.*/",
con->name);
else
sprintf(pos,
"/* Definition of constraint %d was originally here.*/",
node->op1.con_id);
pos += strlen(pos);
return;
}
case DEFINE_BOUNDARY_:
{ struct boundary *bdry = web.boundaries+node->op1.bdry_id;
if ( bdry->attr & NAMED_THING )
sprintf(pos,
"/* Definition of boundary %s was originally here.*/",
bdry->name);
else
sprintf(pos,
"/* Definition of boundary %d was originally here.*/",
node->op1.con_id);
pos += strlen(pos);
return;
}
case DEFINE_EXTRA_:
ex = EXTRAS(node->op2.eltype)+node->op1.extranum;
sprintf(pos,"define %s attribute %s %s",
typenames[node->op2.eltype],ex->name, datatype_name[ex->type]);
pos += strlen(pos);
if ( ex->code.start )
{ strcat(pos," function "); pos += strlen(pos);
/*current_proc_locals[++current_proc_depth] = ex->locals;*/
exprint_recur(ex->code.root,prec_parent);
/*current_proc_depth--;*/
}
break;
case DEFINE_EXTRA_INDEX_:
exprint_recur(node+node->left,prec_parent);
exprint_recur(node+node->right,prec_parent);
break;
case DEFINE_ARRAY_:
sprintf(pos,"define %s %s",globals(node->op1.name_id)->name,
datatype_name[node->op2.valtype]);
pos += strlen(pos);
exprint_recur(node+node->left,prec_parent);
break;
case DEFINE_FIXED_LOCAL_ARRAY_:
{ struct global *g = globals(node->op1.name_id);
struct array *a = g->attr.arrayptr;
int i;
sprintf(pos,"define %s %s",g->name,
datatype_name[node->op2.valtype]);
pos += strlen(pos);
for ( i = 0 ; i < a->dim ; i++ )
{ sprintf(pos,"[%d]",a->sizes[i]);
pos += strlen(pos);
}
}
break;
case ARRAY_EVAL_:
exprint_recur(node+node->left,prec_parent);
exprint_recur(node+node->right,prec_parent);
break;
case ARRAY_HEAD_:
exprint_recur(node+node->left,prec_parent);
break;
case ARRAYASSIGN:
sprintf(pos,"%s",globals(node->op2.name_id)->name);
pos += strlen(pos);
exprint_recur(node+node->left,prec_parent);
switch ( node->op1.assigntype )
{ case ASSIGN_: sprintf(pos," := "); break;
case PLUSASSIGN_: sprintf(pos," += "); break;
case SUBASSIGN_: sprintf(pos," -= "); break;
case MULTASSIGN_: sprintf(pos," *= "); break;
case DIVASSIGN_: sprintf(pos," /= "); break;
}
pos += strlen(pos);
exprint_recur(node+node->right,prec_parent);
break;
case ARRAYEVAL:
sprintf(pos,"%s",globals(node->op2.name_id)->name);
pos += strlen(pos);
exprint_recur(node+node->left,prec_parent);
break;
/* whole-array syntax */
case ARRAYIDENT_:
sprintf(pos,"%s",get_name_name(node->op2.name_id,localbase));
pos += strlen(pos);
break;
case ARRAY_ASSIGNOP_FACET_NORMAL_:
case ARRAY_ASSIGNOP_EDGE_VECTOR_ :
case ARRAY_ASSIGNOP_VERTEX_NORMAL_:
case ARRAY_ASSIGNOP_ARRAY_ :
case ARRAY_ASSIGNOP_SCALAR_ :
case ARRAY_ASSIGNOP_S_X_A_:
case ARRAY_ASSIGNOP_A_P_A_:
case ARRAY_ASSIGNOP_A_S_A_:
exprint_recur(node+node->left,prec_parent);
if ( !(node->flags & SET_ASSIGNOP) )
{
switch ( node->op1.assigntype )
{ case ASSIGN_: sprintf(pos," := "); break;
case PLUSASSIGN_: sprintf(pos," += "); break;
case SUBASSIGN_: sprintf(pos," -= "); break;
case MULTASSIGN_: sprintf(pos," *= "); break;
case DIVASSIGN_: sprintf(pos," /= "); break;
}
pos += strlen(pos);
}
exprint_recur(node+node->right,prec_parent);
break;
case ARRAY_ASSIGNOP_SINGLE_:
exprint_recur(node+node->left,prec_parent);
if ( !(node->flags & SET_ASSIGNOP) )
{
switch ( node->op1.assigntype )
{ case ASSIGN_: sprintf(pos," := "); break;
case PLUSASSIGN_: sprintf(pos," += "); break;
case SUBASSIGN_: sprintf(pos," -= "); break;
case MULTASSIGN_: sprintf(pos," *= "); break;
case DIVASSIGN_: sprintf(pos," /= "); break;
}
pos += strlen(pos);
}
else
{ *pos = '('; *(++pos) = 0; /* avoid - after ] */}
exprint_recur(node+node->right,prec_parent);
if ( node->flags & SET_ASSIGNOP )
{ *pos = ')'; *(++pos) = 0; }
break;
case DOT_:
exprint_recur(node+node->left,prec_parent);
sprintf(pos," dot_product ");
pos += strlen(pos);
exprint_recur(node+node->right,prec_parent);
break;
case ARRAY_LVALUE_INDEXED_:
exprint_recur(node+node->left,prec_parent);
exprint_recur(node+node->right,prec_parent);
*pos = ' '; *(++pos) = 0;
break;
case PRINT_ARRAY_LVALUE_:
sprintf(pos,"print ");
pos += strlen(pos);
exprint_recur(node+node->left,prec_parent);
break;
case ATTRIB_LVALUE_:
case ARRAY_VERTEX_NORMAL_:
case ARRAY_EDGE_VECTOR_:
case ARRAY_FACET_NORMAL_:
if ( node->left )
{ exprint_recur(node+node->left,prec_parent);
/* sprintf(pos," %s",get_name_name(node->op2.name_id,localbase)); */
}
if ( node->op1.localnum == 0)
sprintf(pos," %s",get_name_name(node->op2.name_id,localbase));
else
sprintf(pos,".%s",get_name_name(node->op2.name_id,localbase));
pos += strlen(pos);
break;
case ARRAY_RVALUE_:
exprint_recur(node+node->left,PREC_MUL);
sprintf(pos," %c ",node->op1.intval);
pos += strlen(pos);
exprint_recur(node+node->right,prec_parent);
break;
/* end whole-array syntax */
case SET_CONSTRAINT_GLOBAL:
strcat(pos,"set constraint "); pos += strlen(pos);
exprint_recur(node+node->left,prec_parent);
strcat(pos," global "); pos += strlen(pos);
break;
case UNSET_CONSTRAINT_GLOBAL:
strcat(pos,"unset constraint "); pos += strlen(pos);
exprint_recur(node+node->left,prec_parent);
strcat(pos," global "); pos += strlen(pos);
break;
case SET_CONSTRAINT_NAME_GLOBAL:
sprintf(pos,"set constraint %s global",
get_constraint(node->op3.connum)->name);
pos += strlen(pos);
break;
case UNSET_CONSTRAINT_NAME_GLOBAL:
sprintf(pos,"unset constraint %s global",
get_constraint(node->op3.connum)->name);
pos += strlen(pos);
break;
case RESET_COUNTS_:
strcat(pos,"reset_counts"); pos += strlen(pos);
return;
case FLUSH_COUNTS_:
strcat(pos,"flush_counts"); pos += strlen(pos);
return;
case PRINT_PROFILING_:
strcat(pos,"print profiling"); pos += strlen(pos);
return;
case RESET_PROFILING_:
strcat(pos,"reset_profiling"); pos += strlen(pos);
return;
case PAUSE_:
strcat(pos,"pause"); pos += strlen(pos);
return;
case RETURN_:
strcat(pos,"return "); pos += strlen(pos);
if ( node->left )
exprint_recur(node+node->left,prec_parent);
return;
case DATE_AND_TIME_:
strcat(pos,"date_and_time"); pos += strlen(pos);
return;
case BREAK_:
if ( node->op2.breakdepth > 1 )
sprintf(pos,"break %d",node->op2.breakdepth);
else strcat(pos,"break ");
pos += strlen(pos);
return;
case CONTINUE_:
if ( node->op2.breakdepth > 1 )
sprintf(pos,"continue %d",node->op2.breakdepth);
else strcat(pos,"continue ");
pos += strlen(pos);
return;
case HISTORY_:
strcat(pos,"history "); pos += strlen(pos);
return;
case GET_TRANSFORM_EXPR_:
strcat(pos,"transform_expr "); pos += strlen(pos);
return;
case WARNING_MESSAGES_:
strcat(pos,"warning_messages "); pos += strlen(pos);
return;
case DATAFILENAME_:
strcat(pos,"datafilename "); pos += strlen(pos);
return;
case REPEAT_:
exprint_recur(node+node->right,prec_parent);
nn = node + node->left;
exprint_recur(nn+nn->left,prec_parent);
return;
case EXPRLIST_:
exprint_recur(node+node->left,prec_parent);
if ( node->right )
{ sprintf(pos,", "); pos += 2;
exprint_recur(node+node->right,prec_parent);
}
return;
case QUOTATION_:
print_quote(node->op1.string);
return;
case SPRINTFHEAD_:
case PRESPRINTF_:
sprintf(pos,"sprintf ");
pos += strlen(pos);
if ( node->op1.string ) print_quote(node->op1.string);
else exprint_recur(node+node->left,prec_parent);
return;
case PREPRINTF_:
case PRINTFHEAD_:
sprintf(pos,"printf ");
pos += strlen(pos);
if ( node->op1.string ) print_quote(node->op1.string);
else exprint_recur(node+node->left,prec_parent);
return;
case ERRPRINTFHEAD_:
sprintf(pos,"errprintf ");
pos += strlen(pos);
if ( node->op1.string ) print_quote(node->op1.string);
else exprint_recur(node+node->left,prec_parent);
return;
case BINARY_PRINTFHEAD_:
sprintf(pos,"binary_printf ");
pos += strlen(pos);
if ( node->op1.string ) print_quote(node->op1.string);
else exprint_recur(node+node->left,prec_parent);
return;
case PRINTF_:
case BINARY_PRINTF_:
case ERRPRINTF_:
case SPRINTF_:
exprint_recur(node+node->left,prec_parent);
strcat(pos++,",");
exprint_recur(node+node->right,prec_parent);
return;
case STRPRINT_:
case PRINT_:
case EPRINT_:
sprintf(pos,"print "); pos += strlen(pos);
exprint_recur(node+node->left,prec_parent);
return;
case PRINT_LETTER_:
sprintf(pos,"print %c ",node->op1.name_id);
pos += strlen(pos);
return;
case PRINT_PROCEDURE_:
case PRINT_ARRAY_:
sprintf(pos,"print %s ",globals(node->op1.name_id)->name);
pos += strlen(pos);
return;
case PRINT_ARRAYPART_:
sprintf(pos,"print %s",globals(node[node->left].op1.name_id)->name);
pos += strlen(pos);
exprint_recur(node+node->left,prec_parent);
return;
case PRINT_VERTEXNORMAL_:
sprintf(pos,"print ");
pos += strlen(pos);
exprint_recur(node+node->left,prec_parent);
strcat(pos,".vertexnormal");
pos += strlen(pos);
return;
case PRINT_ATTR_ARRAY_:
sprintf(pos,"print ");
pos += strlen(pos);
exprint_recur(node+node->left,prec_parent);
sprintf(pos,".%s",EXTRAS(node->op2.eltype)[node->op3.extranum].name);
pos += strlen(pos);
if ( node->right )
exprint_recur(node+node->right,prec_parent);
return;
case PRINT_PERM_PROCEDURE_:
sprintf(pos,"print %s ",perm_globals(node->op1.name_id)->name);
pos += strlen(pos);
return;
case EXPRINT_PROCEDURE_:
sprintf(pos,"exprint %s ",globals(node->op1.name_id)->name);
pos += strlen(pos);
return;
case ELSE_: /* root of IF */
exprint_recur(node+node->left,prec_parent); /* IF part */
if ( node->right )
{ sprintf(pos," else "); pos += strlen(pos);
newline();
exprint_recur(node+node->right,prec_parent); /* command */
}
bracket_depth--;
return;
case IF_:
exprint_recur(node+node->left,prec_parent); /* IF part */
exprint_recur(node+node->right,prec_parent); /* command */
return;
case IFTEST_:
sprintf(pos,"if ( "); pos += strlen(pos);
exprint_recur(node+node->left,prec_parent); /* expr */
sprintf(pos," ) then "); pos += strlen(pos);
bracket_depth++;
newline();
return;
case WHILE_END_:
exprint_recur(node+node->left,prec_parent); /* test part */
sprintf(pos," do "); pos += strlen(pos);
bracket_depth++;
if ( node->right )
{ newline();
exprint_recur(node+node->right,prec_parent); /* command */
} else
{ strcat(pos," ;"); pos += strlen(pos); }
bracket_depth--;
return;
case WHILE_TOP_:
sprintf(pos,"while ("); pos += strlen(pos);
exprint_recur(node+node->left,prec_parent); /* expr */
strcat(pos,") "); pos += strlen(pos);
return;
case DO_TOP_:
exprint_recur(node+node->right,prec_parent); /* command */
return;
case DO_END_:
sprintf(pos,"do "); pos += strlen(pos);
bracket_depth++;
newline();
exprint_recur(node+node->left,prec_parent); /* command */
bracket_depth--;
newline();
sprintf(pos," while ("); pos += strlen(pos);
exprint_recur(node+node->right,prec_parent); /* expr */
strcat(pos,") "); pos += strlen(pos);
return;
case FOR_END_:
sprintf(pos,"for ( "); pos += strlen(pos);
exprint_recur(node+node->left,prec_parent); /* FOR_TOP_ */
sprintf(pos," ) "); pos += strlen(pos);
bracket_depth++;
newline();
if ( node->right )
exprint_recur(node+node->right,prec_parent); /* command3 */
else { strcat(pos," ;") ; pos += strlen(pos); } /* empty command3 */
bracket_depth--;
newline();
return;
case FOR_TOP_:
exprint_recur(node+node->left,prec_parent); /* FOR_HEAD_ */
sprintf(pos," ; "); pos += strlen(pos);
exprint_recur(node+node->right,prec_parent); /* command2 */
return;
case FOR_HEAD_:
exprint_recur(node+node->left,prec_parent); /* FOR_ENTRY */
sprintf(pos," ; "); pos += strlen(pos);
exprint_recur(node+node->right,prec_parent); /* expr */
return;
case FOR_ENTRY_:
exprint_recur(node+node->left,prec_parent); /* command1 */
return;
case REDIRECT_:
if ( node->left )
{ strcat(pos,">> "); pos += strlen(pos);
exprint_recur(node+node->left,prec_parent); /* command */
}
else
sprintf(pos,">> \"%s\" ",node->op1.string); pos += strlen(pos);
return;
case REDIRECTOVER_:
if ( node->left )
{ strcat(pos,">>> "); pos += strlen(pos);
exprint_recur(node+node->left,prec_parent); /* command */
}
else
sprintf(pos,">>> \"%s\" ",node->op1.string); pos += strlen(pos);
return;
case PIPE_:
if ( node->left )
{ strcat(pos,"| "); pos += strlen(pos);
exprint_recur(node+node->left,prec_parent); /* command */
}
else
sprintf(pos,"| \"%s\" ",node->op1.string); pos += strlen(pos);
return;
case PIPE_END_:
case REDIRECT_END_:
exprint_recur(node+node->right,prec_parent); /* command */
exprint_recur(node+node->left,prec_parent); /* pipe */
return;
case SINGLE_REDEFD_:
sprintf(pos,"%c ",node->op1.letter);
pos += strlen(pos);
return;
case SINGLE_LETTER_:
if ( single_redefine[node->op1.letter].start )
sprintf(pos,"'%c' ",node->op1.letter);
else sprintf(pos,"%c ",node->op1.letter);
pos += strlen(pos);
return;
/* toggles */ case QUIETGO_: case QUIETLOAD_: case SLICE_VIEW_:
case CLIP_VIEW_: case STAR_FINAGLING_: case FORCE_DELETION_:
case KUSNER_: case ESTIMATE_: case DETURCK_: case HOMOTHETY_:
case SQGAUSS_: case AUTOPOP_: case AUTOCHOP_: case QUIET_:
case OLD_AREA_: case APPROX_CURV_: case RUNGE_KUTTA_:
case CHECK_INCREASE_: case DEBUG_: case MEAN_CURV_: case RIBIERE_CG_:
case DIFFUSION_: case GRAVITY_: case CONJ_GRAD_: case TRANSFORMS_:
case CONF_EDGE_SQCURV_: case EFFECTIVE_AREA_: case AREA_FIXED_:
case RAW_CELLS_: case CONNECTED_CELLS_: case CLIPPED_CELLS_:
case THICKEN_: case SHOW_INNER_: case SHOW_OUTER_: case COLORMAP_:
case HESSIAN_DIFF_: case POST_PROJECT_: case MEAN_CURV_INT_:
case OPTIMIZE_: case NORMAL_CURVATURE_: case DIV_NORMAL_CURVATURE_:
case SHADING_: case FACET_COLORS_: case BOUNDARY_CURVATURE_:
case NORMAL_MOTION_: case PINNING_: case VIEW_4D_: case MEMDEBUG_:
case METRIC_CONVERSION_: case AUTORECALC_: case GV_BINARY_:
case SELF_SIMILAR_: case AUTODISPLAY_: case FORCE_POS_DEF_:
case ASSUME_ORIENTED_: case HESSIAN_QUIET_: case JIGGLE_TOGGLE_:
case HESSIAN_NORMAL_: case YSMP_: case BUNCH_KAUFMAN_:
case QUANTITIES_ONLY_: case LINEAR_METRIC_:
case SQUARED_GRADIENT_: case H_INVERSE_METRIC_:
case HESSIAN_DOUBLE_NORMAL_: case INTERP_BDRY_PARAM_:
case HESSIAN_NORMAL_ONE_: case PSCOLORFLAG_: case GRIDFLAG_:
case CROSSINGFLAG_: case LABELFLAG_: case SHOW_ALL_QUANTITIES_:
case HESSIAN_NORMAL_PERP_: case HESSIAN_SPECIAL_NORMAL_: case ITDEBUG_:
case METIS_FACTOR_: case VOLGRADS_EVERY_: case ZENER_DRAG_:
case BACKCULL_: case INTERP_NORMALS_: case TORUS_FILLED_: case VERBOSE_:
case AMBIENT_PRESSURE_: case DIRICHLET_MODE_: case SOBOLEV_MODE_:
case KRAYNIKPOPVERTEX_FLAG_: case FUNCTION_QUANTITY_SPARSE_:
case KRAYNIKPOPEDGE_FLAG_: case VISIBILITY_TEST_: case SPARSE_CONSTRAINTS_:
case BLAS_FLAG_: case AUGMENTED_HESSIAN_: case BREAK_AFTER_WARNING_:
case RGB_COLORS_FLAG_: case CIRCULAR_ARC_DRAW_: case BEZIER_BASIS_:
case SMOOTH_GRAPH_: case MPI_DEBUG_: case POP_DISJOIN_:
case POP_TO_EDGE_: case POP_TO_FACE_: case POP_ENJOIN_:
case FULL_BOUNDING_BOX_: case BIG_ENDIAN_: case LITTLE_ENDIAN_:
case AUTOPOP_QUARTIC_: case IMMEDIATE_AUTOPOP_:
sprintf(pos,"%s %s ",keywordname(node->type),
node->op1.toggle_state==ON_?"ON":"OFF"); pos += strlen(pos);
break;
case LOGFILE_TOGGLE_:
sprintf(pos,"logfile %s ",
node->op1.toggle_state==ON_?"ON":"OFF"); pos += strlen(pos);
break;
case KEYLOGFILE_TOGGLE_:
sprintf(pos,"keylogfile %s ",
node->op1.toggle_state==ON_?"ON":"OFF"); pos += strlen(pos);
break;
case GEOMVIEW_TOGGLE_:
sprintf(pos,"geomview %s ",
node->op1.toggle_state==ON_?"ON":"OFF"); pos += strlen(pos);
break;
case GEOMPIPE_TOGGLE_:
sprintf(pos,"geompipe %s ",
node->op1.toggle_state==ON_?"ON":"OFF"); pos += strlen(pos);
break;
case GEOMPIPE_:
sprintf(pos,"geompipe "); pos += strlen(pos);
exprint_recur(node+node->left,prec_parent);
break;
case POSTSCRIPT_:
sprintf(pos,"postscript "); pos += strlen(pos);
exprint_recur(node+node->left,prec_parent);
break;
case BINARY_OFF_FILE_:
sprintf(pos,"binary_off_file "); pos += strlen(pos);
exprint_recur(node+node->left,prec_parent);
break;
case OOGLFILE_:
sprintf(pos,"ooglfile "); pos += strlen(pos);
exprint_recur(node+node->left,prec_parent);
break;
case TOGGLEVALUE:
sprintf(pos,"(%s) ",keywordname(node->op1.toggle_id));
pos += strlen(pos);
break;
case GET_INTERNAL_:
sprintf(pos,"%s",keywordname(node->op1.name_id));
pos += strlen(pos);
break;
case PROCEDURE_:
sprintf(pos,"%s ",globals(node->op1.name_id)->name);
pos += strlen(pos);
break;
case PERM_PROCEDURE_:
sprintf(pos,"%s ",perm_globals(node->op1.name_id)->name);
pos += strlen(pos);
break;
case FIX_PARAMETER_:
sprintf(pos,"fix %s",globals(node->op1.name_id)->name);
pos += strlen(pos);
break;
case UNFIX_PARAMETER_:
sprintf(pos,"unfix %s",globals(node->op1.name_id)->name);
pos += strlen(pos);
break;
case FIX_QUANTITY_:
sprintf(pos,"fix %s",GEN_QUANT(node->op1.quant_id)->name);
pos += strlen(pos);
break;
case UNFIX_QUANTITY_:
sprintf(pos,"unfix %s",GEN_QUANT(node->op1.quant_id)->name);
pos += strlen(pos);
break;
case SET_Q_FIXED_:
sprintf(pos,"set %s fixed",GEN_QUANT(node->op1.quant_id)->name);
pos += strlen(pos);
break;
case SET_Q_ENERGY_:
sprintf(pos,"set %s energy",GEN_QUANT(node->op1.quant_id)->name);
pos += strlen(pos);
break;
case SET_Q_INFO_:
sprintf(pos,"set %s info_only",GEN_QUANT(node->op1.quant_id)->name);
pos += strlen(pos);
break;
case SET_Q_CONSERVED_:
sprintf(pos,"set %s conserved",GEN_QUANT(node->op1.quant_id)->name);
pos += strlen(pos);
break;
case SET_INTERNAL_:
sprintf(pos,"%s %s ",keywordname(node->op1.name_id),
assign_symbol(node->op2.assigntype));
pos += strlen(pos);
exprint_recur(node+node->left,prec_parent);
break;
case VIEW_MATRIX_LVALUE_:
sprintf(pos,"view_matrix["); pos += strlen("view_matrix[");
exprint_recur(node+node->left,prec_parent);
sprintf(pos,"]["); pos += 2;
exprint_recur(node+node->right,prec_parent);
sprintf(pos,"]"); pos += 1;
break;
case SET_VIEW_MATRIX_:
exprint_recur(node+node->left,prec_parent);
sprintf(pos," := "); pos += 4;
exprint_recur(node+node->right,prec_parent);
break;
case SET_SCALE_:
sprintf(pos,"m "); pos += strlen(pos);
exprint_recur(node+node->left,prec_parent);
break;
case SET_OPTIMIZE_:
sprintf(pos,"optimize "); pos += strlen(pos);
exprint_recur(node+node->left,prec_parent);
break;
case SET_FIXED_AREA_:
sprintf(pos,"area_fixed := "); pos += strlen(pos);
exprint_recur(node+node->left,prec_parent);
break;
case SET_GAP_CONSTANT_:
sprintf(pos,"gap_constant := "); pos += strlen(pos);
exprint_recur(node+node->left,prec_parent);
break;
case SKINNY_:
sprintf(pos,"K "); pos += strlen(pos);
exprint_recur(node+node->left,prec_parent);
break;
case TORDUP_:
sprintf(pos,"y "); pos += strlen(pos);
exprint_recur(node+node->left,prec_parent);
break;
case SET_MODEL_:
sprintf(pos,"M "); pos += strlen(pos);
exprint_recur(node+node->left,prec_parent);
break;
case INVOKE_P_MENU_:
sprintf(pos,"P "); pos += strlen(pos);
exprint_recur(node+node->left,prec_parent);
break;
case SET_GRAVITY_:
switch ( node->op1.assigntype )
{ case ASSIGN_: sprintf(pos,"G "); break;
case PLUSASSIGN_: sprintf(pos,"gravity += "); break;
case SUBASSIGN_: sprintf(pos,"gravity -= "); break;
case MULTASSIGN_: sprintf(pos,"gravity *= "); break;
case DIVASSIGN_: sprintf(pos,"gravity /= "); break;
}
pos += strlen(pos);
exprint_recur(node+node->left,prec_parent);
break;
case SET_DIFFUSION_:
sprintf(pos,"diffusion := "); pos += strlen(pos);
exprint_recur(node+node->left,prec_parent);
break;
case SET_THICKEN_:
sprintf(pos,"thicken := "); pos += strlen(pos);
exprint_recur(node+node->left,prec_parent);
break;
case SET_AUTOCHOP_:
sprintf(pos,"autochop := "); pos += strlen(pos);
exprint_recur(node+node->left,prec_parent);
break;
case SET_AMBIENT_PRESSURE_:
sprintf(pos,"p "); pos += strlen(pos);
exprint_recur(node+node->left,prec_parent);
break;
case ZOOM_:
sprintf(pos,"zoom "); pos+=strlen(pos);
if ( node->left )
{ exprint_recur(node+node->left,prec_parent);
exprint_recur(node+node->right,prec_parent);
}
break;
case CHDIR_:
case SYSTEM_:
case EXEC_: case PARALLEL_EXEC_:
case READ_:
case LOAD_:
case PERMLOAD_:
case ADDLOAD_:
case SHOW_TRANS_:
case TRANSFORM_EXPR_:
case GEOMVIEW_:
sprintf(pos,"%s ",keywordname(node->type));
pos += strlen(pos);
exprint_recur(node+node->left,prec_parent);
break;
case TASK_EXEC_:
sprintf(pos,"%s ",keywordname(node->type));
pos += strlen(pos);
exprint_recur(node+node->left,prec_parent);
*pos = ','; pos++;
exprint_recur(node+node->right,prec_parent);
break;
case VIEW_TRANSFORM_PARITY_:
strcat(pos,"view_transform_parity["); pos += strlen(pos);
exprint_recur(node+node->left,prec_parent);
strcat(pos,"]"); pos++;
break;
case VIEW_TRANSFORM_SWAP_COLORS_:
strcat(pos,"view_transform_swap_colors["); pos += strlen(pos);
exprint_recur(node+node->left,prec_parent);
strcat(pos,"]"); pos++;
break;
case VIEW_TRANSFORMS_NOP_:
strcat(pos,"view_transforms["); pos += strlen(pos);
exprint_recur(node+node->left,prec_parent);
strcat(pos,"]["); pos += 2;
exprint_recur(node+node->right,prec_parent);
break;
case VIEW_TRANSFORMS_ELEMENT_:
exprint_recur(node+node->left,prec_parent);
strcat(pos,"]["); pos += 2;
exprint_recur(node+node->right,prec_parent);
*(pos++) = ']';
break;
case IS_DEFINED_:
sprintf(pos,"is_defined(");
pos += strlen(pos);
exprint_recur(node+node->left,prec_parent);
*(pos++) = ')';
break;
case DUMP_:
sprintf(pos,"dump ");
pos += strlen(pos);
if ( node->left )
exprint_recur(node+node->left,prec_parent);
break;
case SET_COLORMAP_:
sprintf(pos,"colormap := ");
pos += strlen(pos);
exprint_recur(node+node->left,prec_parent);
break;
case SHOW_VOL_: case CHECK_: case LONG_JIGGLE_: case RAW_VERAVG_:
case STABILITY_TEST_: case UTEST_: case GO_: case SHELL_:
case ALICE_: case RECALC_: case COUNTS_: case RAWEST_VERAVG_:
case EXTRAPOLATE_: case LINEAR_: case QUADRATIC_: case REBODY_:
case HESSIAN_: case SHOWQ_: case CLOSE_SHOW_: case HESSIAN_MENU_:
case DIRICHLET_: case SOBOLEV_: case REORDER_STORAGE_:
case DIRICHLET_SEEK_: case SOBOLEV_SEEK_: case CONVERT_TO_QUANTS_:
case RENUMBER_ALL_: case DUMP_MEMLIST_: case FREE_DISCARDS_:
case REPARTITION_: case SUBCOMMAND_: case ABORT_:
case SIMPLEX_TO_FE_:
sprintf(pos,"%s ",keywordname(node->type)); pos+=strlen(pos);
break;
case BURCHARD_:
sprintf(pos,"%s %d ",keywordname(node->type),node->op1.maxsteps);
pos+=strlen(pos);
break;
case SHOW_END_:
if ( node[node->left].type == SHOW_ )
sprintf(pos,"show_expr "); /* prevent extraneous shows from dump */
else sprintf(pos,"show_expr ");
pos += strlen(pos);
exprint_recur(node+node->right,prec_parent);
break;
case SET_PROC_END_:
{ struct global *g = globals(node[node->left].op1.name_id);
if ( node[node->left].type == REDEFINE_SINGLE_ )
sprintf(pos,"%c :::= ",node[node->left].op1.letter);
else if ( g->flags & PERMANENT )
sprintf(pos,"%s ::= ",g->name);
else sprintf(pos,"%s := ",g->name);
pos += strlen(pos);
if ( node[node->right].type != COMMAND_BLOCK_ )
{ strcat(pos,"{"); pos++; }
current_proc_locals[++current_proc_depth] = g->value.proc.locals;
exprint_recur(node+node->right,prec_parent);
current_proc_depth--;
if ( node[node->right].type != COMMAND_BLOCK_ )
{ strcat(pos,"}"); pos++; }
break;
}
case SET_PERM_PROC_END_:
sprintf(pos,"%s ::= ",perm_globals(node[node->left].op1.name_id)->name);
pos += strlen(pos);
if ( node[node->right].type != COMMAND_BLOCK_ )
{ strcat(pos,"{"); pos++; }
exprint_recur(node+node->right,prec_parent);
if ( node[node->right].type != COMMAND_BLOCK_ )
{ strcat(pos,"}"); pos++; }
break;
case ARGLIST_:
{ struct global *g;
if ( node->op1.name_id == 0 ) break; /* empty list */
g = globals(node->op1.name_id);
if ( node->left )
{ exprint_recur(node+node->left,prec_parent); /* arglist */
strcat(pos,","); pos++;
}
sprintf(pos,"%s %s",datatype_name[node->op3.argtype],g->name);
pos += strlen(pos);
break;
}
case FUNCTION_CALL_:
{ struct global *g = globals(node->op1.name_id);
sprintf(pos,"%s(",g->name);
pos += strlen(pos);
if ( node->left )
exprint_recur(node+node->left,prec_parent); /* arglist */
strcat(pos,")"); pos++;
break;
}
case FUNCTION_CALL_RETURN_:
exprint_recur(node+node->left,prec_parent); /* FUNCTION_CALL_ */
break;
case FUNCTION_START_: break;
case FUNCTION_DEF_START_: break;
case FUNCTION_PROTO_START_: break;
case FUNCTION_HEAD_:
exprint_recur(node+node->right,prec_parent); /* arglist */
break;
case SET_FUNCTION_:
case FUNCTION_PROTO_:
{ struct global *g = globals(node[node->left].op1.name_id);
sprintf(pos,"function %s %s (",datatype_name[node->op4.ret_type],
g->name);
pos += strlen(pos);
current_proc_locals[++current_proc_depth] = g->value.proc.locals;
exprint_recur(node+node->left,prec_parent); /* arglist */
if ( node->type == SET_FUNCTION_ )
{ strcat(pos,")\n"); pos += strlen(pos);
exprint_recur(node+node->right,prec_parent); /* body */
}
else { strcat(pos,");\n"); pos += strlen(pos); }
current_proc_depth--;
break;
}
case PROCEDURE_CALL_:
sprintf(pos,"%s(",globals(node->op1.name_id)->name);
pos += strlen(pos);
if ( node->left )
exprint_recur(node+node->left,prec_parent); /* arglist */
strcat(pos,")"); pos++;
break;
case PROCEDURE_CALL_RETURN_:
exprint_recur(node+node->left,prec_parent); /* PROCEDURE_CALL_ */
break;
case PROCEDURE_START_: break;
case PROCEDURE_DEF_START_: break;
case PROCEDURE_PROTO_START_: break;
case PROCEDURE_HEAD_:
exprint_recur(node+node->right,prec_parent); /* arglist */
break;
case SET_ARGSPROC_:
case PROCEDURE_PROTO_:
{ struct global *g = globals(node[node->left].op1.name_id);
sprintf(pos,"procedure %s (",g->name);
pos += strlen(pos);
current_proc_locals[++current_proc_depth] = g->value.proc.locals;
exprint_recur(node+node->left,prec_parent); /* arglist */
if ( node->type == SET_ARGSPROC_ )
{ strcat(pos,")\n"); pos += strlen(pos);
exprint_recur(node+node->right,prec_parent); /* body */
}
else { strcat(pos,");\n"); pos += strlen(pos); }
current_proc_depth--;
break;
}
case DEFINE_IDENT_:
sprintf(pos,"define %s %s",globals(node->op1.name_id)->name,
datatype_name[node->op2.valtype]);
pos += strlen(pos);
break;
case SET_DELTA_:
sprintf(pos,"%s.pdelta",globals(node->op1.name_id)->name);
pos += strlen(pos);
switch ( node->op2.assigntype )
{ case ASSIGN_: sprintf(pos," := "); break;
case PLUSASSIGN_: sprintf(pos," += "); break;
case SUBASSIGN_: sprintf(pos," -= "); break;
case MULTASSIGN_: sprintf(pos," *= "); break;
case DIVASSIGN_: sprintf(pos," /= "); break;
}
pos += strlen(pos);
exprint_recur(node+node->left,prec_parent);
break;
case SET_PARAM_SCALE:
sprintf(pos,"%s.pscale",globals(node->op1.name_id)->name);
pos += strlen(pos);
switch ( node->op2.assigntype )
{ case ASSIGN_: sprintf(pos," := "); break;
case PLUSASSIGN_: sprintf(pos," += "); break;
case SUBASSIGN_: sprintf(pos," -= "); break;
case MULTASSIGN_: sprintf(pos," *= "); break;
case DIVASSIGN_: sprintf(pos," /= "); break;
}
pos += strlen(pos);
exprint_recur(node+node->left,prec_parent);
break;
case SET_GLOBAL_: case SET_SGLOBAL_:
{ struct global *g = globals(node->op1.name_id);
if ( g->flags & PERMANENT )
sprintf(pos,"%s ::= ",g->name);
else sprintf(pos,"%s := ",g->name);
pos += strlen(pos);
exprint_recur(node+node->left,prec_parent);
break;
}
case SET_PERM_GLOBAL_: case SET_PERM_SGLOBAL_:
sprintf(pos,"%s ::= ",globals(node->op1.name_id)->name);
pos += strlen(pos);
exprint_recur(node+node->left,prec_parent);
break;
case PLUSASSIGN_:
sprintf(pos,"%s += ",globals(node->op1.name_id)->name);
pos += strlen(pos);
exprint_recur(node+node->left,prec_parent);
break;
case SUBASSIGN_:
sprintf(pos,"%s -= ",globals(node->op1.name_id)->name);
pos += strlen(pos);
exprint_recur(node+node->left,prec_parent);
break;
case MULTASSIGN_:
sprintf(pos,"%s *= ",globals(node->op1.name_id)->name);
pos += strlen(pos);
exprint_recur(node+node->left,prec_parent);
break;
case DIVASSIGN_:
sprintf(pos,"%s /= ",globals(node->op1.name_id)->name);
pos += strlen(pos);
exprint_recur(node+node->left,prec_parent);
break;
case SIZEOF_ATTR_:
sprintf(pos,"sizeof(%s)",
EXTRAS(node->op2.eltype)[node->op1.extranum].name);
pos += strlen(pos);
break;
case SIZEOF_ARRAY_:
sprintf(pos,"sizeof(%s)",globals(node->op1.name_id)->name);
pos += strlen(pos);
break;
case SIZEOF_STRING_:
sprintf(pos,"sizeof(");
pos += strlen(pos);
exprint_recur(node+node->left,prec_parent);
strcat(pos,")");
pos++;
break;
case LAGRANGE_:
sprintf(pos,"%s ",keywordname(node->type)); pos += strlen(pos);
exprint_recur(node+node->left,prec_parent);
return;
case LANCZOS_:
case EIGENPROBE_:
sprintf(pos,"%s ",keywordname(node->type)); pos += strlen(pos);
if ( node->right )
{ strcat(pos,"("); pos++;
exprint_recur(node+node->left,prec_parent);
strcat(pos,","); pos++;
exprint_recur(node+node->right,prec_parent);
strcat(pos,")"); pos++;
}
else exprint_recur(node+node->left,prec_parent);
return;
case RITZ_:
sprintf(pos,"%s(",keywordname(node->type)); pos += strlen(pos);
exprint_recur(node+node->left,prec_parent);
strcat(pos,","); pos++;
exprint_recur(node+node->right,prec_parent);
strcat(pos,")"); pos++;
return;
case GET_TORUS_PERIODS_:
sprintf(pos,"torus_periods"); pos += strlen(pos);
strcat(pos++,"[");
exprint_recur(node+node->left,prec_parent);
strcat(pos,"]["); pos+=2;
exprint_recur(node+node->right,prec_parent);
strcat(pos++,"]");
return;
case GET_INVERSE_PERIODS_:
sprintf(pos,"inverse_periods"); pos += strlen(pos);
strcat(pos++,"[");
exprint_recur(node+node->left,prec_parent);
strcat(pos,"]["); pos+=2;
exprint_recur(node+node->right,prec_parent);
strcat(pos++,"]");
return;
case HESSIAN_SADDLE_:
case HESSIAN_SEEK_:
sprintf(pos,"%s ",keywordname(node->type)); pos += strlen(pos);
if ( node->left )
exprint_recur(node+node->left,prec_parent);
return;
case MOVE_:
case AREAWEED_:
case EDGEWEED_:
case METIS_:
case METIS_READJUST_:
case KMETIS_:
case BODY_METIS_:
case NOTCH_:
case EDGEDIVIDE_:
sprintf(pos,"%s ",keywordname(node->type)); pos += strlen(pos);
exprint_recur(node+node->left,prec_parent);
return;
case OMETIS_:
sprintf(pos,"%s ",keywordname(node->type)); pos += strlen(pos);
if ( node->left )
exprint_recur(node+node->left,prec_parent);
return;
case JIGGLE_:
strcat(pos,"j "); pos += 2;
exprint_recur(node+node->left,prec_parent);
return;
case LIST_PROCS_:
sprintf(pos,"list procedures "); pos+=strlen(pos);
break;
case LIST_ATTRIBUTES_:
sprintf(pos,"list attributes "); pos+=strlen(pos);
break;
case LIST_QUANTITY_:
sprintf(pos,"list quantity %s",GEN_QUANT(node->op1.quant_id)->name);
pos += strlen(pos);
break;
case LIST_METHOD_INSTANCE_:
sprintf(pos,"list method_instance %s",
METH_INSTANCE(node->op1.meth_id)->name);
pos += strlen(pos);
break;
case LIST_CONSTRAINT_:
{
if ( node->op1.con_id > 0 )
{ sprintf(pos,"list constraint %s",
get_constraint(node->op1.con_id)->name);
pos += strlen(pos);
}
else
{ sprintf(pos,"list constraint ");
pos += strlen(pos);
exprint_recur(node+node->left,prec_parent);
}
}
break;
case LIST_BOUNDARY_:
{
if ( node->op1.bdry_id > 0 )
{ sprintf(pos,"list constraint %s",
web.boundaries[node->op1.bdry_id].name);
pos += strlen(pos);
}
else
{ sprintf(pos,"list boundary ");
pos += strlen(pos);
exprint_recur(node+node->left,prec_parent);
}
}
break;
case TOPINFO_:
sprintf(pos,"list topinfo "); pos+=strlen(pos);
break;
case BOTTOMINFO_:
sprintf(pos,"list bottominfo "); pos+=strlen(pos);
break;
case AGGREGATE_END_:
exprint_recur(node+node->right,prec_parent);
return;
case LIST_: case DELETE_: case REFINE_: case DISSOLVE_: case POP_:
case FIX_: case UNFIX_: case EDGESWAP_: case VERTEX_AVERAGE_:
case RAW_VERTEX_AVERAGE_: case RAWEST_VERTEX_AVERAGE_:
case EQUIANGULATE_: case POP_EDGE_TO_TRI_: case POP_TRI_TO_EDGE_:
case POP_QUAD_TO_QUAD_: case T1_EDGESWAP_:
case REVERSE_ORIENTATION_:
case WHEREAMI_COMMAND_:
sprintf(pos,"%s ",keywordname(node->type));
pos += strlen(pos);
exprint_recur(node+node->left,prec_parent);
return;
case SINGLE_ELEMENT_INIT_:
return;
case SINGLE_ELEMENT_:
exprint_recur(node+node->left,prec_parent);
if ( node[node->left].type == INDEXED_SUBTYPE_ ||
node[node->left].type == INDEXED_ELEMENT_ )
if ( node[node->left].op5.string )
{ sprintf(pos," %s ",node[node->left].op5.string);
pos += strlen(pos);
}
return;
case GET_VERTEXNORMAL_:
strcat(pos,"vertexnormal"); pos += strlen(pos);
exprint_recur(node+node->left,prec_parent);
return;
case INDEXED_COORD_:
strcat(pos,"x"); pos += 1;
exprint_recur(node+node->left,prec_parent);
return;
case INDEXED_ELEMENT_:
switch ( node->op1.eltype )
{ case VERTEX: strcat(pos,"vertex["); break;
case EDGE: strcat(pos,"edge["); break;
case FACET: strcat(pos,"facet["); break;
case BODY: strcat(pos,"body["); break;
case FACETEDGE: strcat(pos,"facetedge["); break;
}
pos += strlen(pos);
exprint_recur(node+node->left,prec_parent);
strcat(pos++,"]");
return;
case INDEXED_SUBTYPE_:
exprint_recur(node+node->left,prec_parent);
sprintf(pos,".%s[",typenames[node->op1.eltype]);
pos += strlen(pos);
exprint_recur(node+node->right,prec_parent);
strcat(pos,"]");
pos += strlen(pos);
return;
case SELF_ELEMENT_:
strcat(pos,"self"); pos+=4; break;
case SINGLE_ELEMENT_EXPR_:
exprint_recur(node+node->left,prec_parent);
break;
case SYMBOL_:
case SYMBOL_ELEMENT_:
sprintf(pos,"%s", node->op5.string);
pos += strlen(pos); break;
case SET_PHASE_:
set_print(node,"set","phase",prec_parent); break;
case SET_DENSITY_:
set_print(node,"set","density",prec_parent); break;
case SET_VOLCONST_:
set_print(node,"set","volconst",prec_parent); break;
case SET_TARGET_:
set_print(node,"set","target",prec_parent); break;
case SET_PRESSURE_:
set_print(node,"set","pressure",prec_parent); break;
case SET_OPACITY_:
set_print(node,"set","opacity",prec_parent); break;
case SET_CONSTRAINT_:
set_print(node,"set","constraint",prec_parent); break;
case SET_CONSTRAINT_NAME:
set_print(node,"set","constraint ",prec_parent);
strcat(pos,get_constraint((int)(node[node->left].op1.real))->name);
pos += strlen(pos); break;
case SET_NAMED_QUANTITY_:
set_print(node,"set","quantity",prec_parent); break;
case UNSET_NAMED_QUANTITY_:
set_print(node,"unset","quantity",prec_parent); break;
case SET_METHOD_INSTANCE_:
set_print(node,"set","method_instance",prec_parent); break;
case UNSET_METHOD_INSTANCE_:
set_print(node,"unset","method_instance",prec_parent); break;
case SET_EXTRA_ATTR_:
{ ex = EXTRAS(node->op3.extra_info >> ESHIFT)
+(node->op3.extra_info & 0xFF);
set_print(node,"set",ex->name,prec_parent);
if ( node->right )
exprint_recur(node+node->right,prec_parent);
}
break;
case SET_COLOR_:
set_print(node,"set","color",prec_parent); break;
case SET_FRONTCOLOR_:
set_print(node,"set","frontcolor",prec_parent); break;
case SET_BACKCOLOR_:
set_print(node,"set","backcolor",prec_parent); break;
case SET_TAG_:
set_print(node,"set","tag",prec_parent); break;
case SET_BACKGROUND_:
set_print(node,"set","background",prec_parent); break;
case SET_COORD_:
{ char cname[10];
if ( (vch == 'X') && (node->op2.coordnum+1 <= 3) )
sprintf(cname,"%c",'x'+node->op2.coordnum);
else
sprintf(cname,"%c%d",vch,node->op2.coordnum+1);
set_print(node,"set",cname,prec_parent);
}
break;
case SET_PARAM_:
{ char cname[10];
sprintf(cname,"P%d",node->op2.coordnum+1);
set_print(node,"set",cname,prec_parent);
}
break;
case UNSET_FIXED_:
set_print(node,"unset","fixed",prec_parent); break;
case SET_FIXED_:
set_print(node,"set","fixed",prec_parent); break;
case UNSET_BARE_:
set_print(node,"unset","bare",prec_parent); break;
case SET_BARE_:
set_print(node,"set","bare",prec_parent); break;
case UNSET_NO_DISPLAY_:
set_print(node,"unset","no_display",prec_parent); break;
case SET_NO_DISPLAY_:
set_print(node,"set","no_display",prec_parent); break;
case UNSET_NONCONTENT_:
set_print(node,"unset","noncontent",prec_parent); break;
case SET_NONCONTENT_:
set_print(node,"set","noncontent",prec_parent); break;
case UNSET_HIT_PARTNER_:
set_print(node,"unset","hit_partner",prec_parent); break;
case SET_HIT_PARTNER_:
set_print(node,"set","hit_partner",prec_parent); break;
case UNSET_NO_REFINE_:
set_print(node,"unset","no_refine",prec_parent); break;
case SET_NO_REFINE_:
set_print(node,"set","no_refine",prec_parent); break;
case UNSET_TRIPLE_PT_:
set_print(node,"unset","triple_point",prec_parent); break;
case SET_ORIENTATION_:
set_print(node,"set","orientation",prec_parent); break;
case UNSET_TETRA_PT_:
set_print(node,"unset","tetra_point",prec_parent); break;
case UNSET_AXIAL_POINT_:
set_print(node,"unset","axial_point",prec_parent); break;
case UNSET_FACET_BODY_:
set_print(node,"unset","body",prec_parent); break;
case SET_FRONTBODY_:
set_print(node,"set","frontbody",prec_parent); break;
case UNSET_FRONTBODY_:
set_print(node,"unset","frontbody",prec_parent); break;
case SET_BACKBODY_:
set_print(node,"set","backbody",prec_parent); break;
case UNSET_BACKBODY_:
set_print(node,"unset","backbody",prec_parent); break;
case UNSET_DENSITY_:
set_print(node,"unset","density",prec_parent); break;
case UNSET_PRESSURE_:
set_print(node,"unset","pressure",prec_parent); break;
case UNSET_VOLUME_:
case UNSET_TARGET_:
set_print(node,"unset","target",prec_parent); break;
case UNSET_CONSTRAINT_:
set_print(node,"unset","constraint",prec_parent);
break;
case UNSET_CONSTRAINT_NAME:
{ char temp[100];
sprintf(temp,"constraint %s",get_constraint(node->op3.connum)->name);
set_print(node,"unset",temp,prec_parent);
pos += strlen(pos);
break;
}
case UNSET_BOUNDARY_:
set_print(node,"unset","boundary",prec_parent); break;
case UNSET_BOUNDARY_NAME:
{ char temp[100];
sprintf(temp,"boundary %s",web.boundaries[node->op3.bdrynum].name);
set_print(node,"unset",temp,prec_parent);
pos += strlen(pos);
break;
}
case SET_INIT_ : break;
case SET_ATTRIBUTE_LOOP_:
{ struct treenode *nnode;
sprintf(pos," set ");
pos += strlen(pos);
nnode = node + node->left;
if ( nnode->type == WHERE_ ) nnode += nnode->left; /* get NEXT_ */
exprint_recur(nnode,prec_parent);
if ( node->right ) exprint_recur(node+node->right,prec_parent);
if ( node[node->left].type == WHERE_ )
{ node+= node->left;
sprintf(pos," where "); pos += strlen(pos);
exprint_recur(node+node->right,prec_parent);
}
}
return;
case FOREACH_:
sprintf(pos,"foreach ");
pos += strlen(pos);
exprint_recur(node+node->left,prec_parent);
sprintf(pos," do ");
pos += strlen(pos);
bracket_depth++;
newline();
exprint_recur(node+node->right,prec_parent);
bracket_depth--;
return;
case MAX_: case MIN_: case SUM_: case AVG_: case COUNT_:
case HISTOGRAM_: case LOGHISTOGRAM_:
sprintf(pos,"%s(",keywordname(node->type));
pos += strlen(pos);
exprint_recur(node+node->left,prec_parent);
sprintf(pos,","); pos++;
exprint_recur(node+node->right,prec_parent);
sprintf(pos,")"); pos++;
return;
case WHERE_:
exprint_recur(node+node->left,prec_parent);
sprintf(pos," where "); pos += strlen(pos);
exprint_recur(node+node->right,prec_parent);
return;
case NEXT_VERTEX_: case NEXT_EDGE_VERTEX_: case NEXT_FACET_VERTEX_:
case NEXT_BODY_VERTEX_: case NEXT_FACETEDGE_:
case NEXT_EDGE_: case NEXT_VERTEX_EDGE_: case NEXT_FACET_EDGE_:
case NEXT_FACET_: case NEXT_VERTEX_FACET_: case NEXT_EDGE_FACET_:
case NEXT_BODY_: case NEXT_VERTEX_BODY_: case NEXT_EDGE_BODY_:
case NEXT_FACET_BODY_:
case NEXT_BODY_FACET_:
case NEXT_BODY_EDGE_:
exprint_recur(node+node->left,prec_parent);
if ( strcmp(node->op5.string,default_name) != 0 )
{ sprintf(pos,"%s ",node->op5.string);
pos += strlen(pos);
}
return;
case INIT_FACETEDGE_:
sprintf(pos,"facetedges "); pos += strlen(pos);
return;
case INIT_VERTEX_:
sprintf(pos,"vertices "); pos += strlen(pos);
return;
case INIT_EDGE_VERTEX_: case INIT_FACET_VERTEX_: case INIT_BODY_VERTEX_:
exprint_recur(node+node->left,prec_parent);
sprintf(pos,".vertices ");
pos += strlen(pos);
return;
case INIT_EDGE_:
sprintf(pos,"edges "); pos += strlen(pos);
return;
case INIT_VERTEX_EDGE_: case INIT_FACET_EDGE_: case INIT_BODY_EDGE_:
exprint_recur(node+node->left,prec_parent);
sprintf(pos,".edges ");
pos += strlen(pos);
return;
case INIT_FACET_:
sprintf(pos,"facets "); pos += strlen(pos);
return;
case INIT_VERTEX_FACET_: case INIT_EDGE_FACET_: case INIT_BODY_FACET_:
exprint_recur(node+node->left,prec_parent);
sprintf(pos,".facets ");
pos += strlen(pos);
return;
case INIT_BODY_:
sprintf(pos,"bodies "); pos += strlen(pos);
break;
case INIT_VERTEX_BODY_: case INIT_EDGE_BODY_: case INIT_FACET_BODY_:
exprint_recur(node+node->left,prec_parent);
sprintf(pos,".bodies ");
pos += strlen(pos);
return;
case PUSH_NAMED_QUANTITY:
sprintf(pos,"%s ",GEN_QUANT(node->op1.quant_id)->name);
pos += strlen(pos);
return;
case PUSH_METHOD_INSTANCE_:
sprintf(pos,"%s ",METH_INSTANCE(node->op1.meth_id)->name);
pos += strlen(pos);
return;
case PUSHCONST:
#ifdef LONGDOUBLE
sprintf(pos,"%1.*Lg",DPREC,node->op1.real);
#else
sprintf(pos,"%1.15g",node->op1.real);
#endif
pos += strlen(pos);
return;
case PUSHPI:
sprintf(pos,"pi");
pos += strlen(pos);
return;
case PUSHE:
sprintf(pos,"e");
pos += strlen(pos);
return;
case PUSHG:
sprintf(pos,"G");
pos += strlen(pos);
return;
case COORD_:
if ( node->left )
{ exprint_recur(node+node->left,PREC_COND);
sprintf(pos,"."); pos += strlen(pos);
}
if ( (vch == 'X') && (node->op2.coordnum+1 <= 3) )
sprintf(msg,"%c",'x'+node->op2.coordnum);
else
sprintf(msg,"%c%d",vch,node->op2.coordnum+1);
print_attr(node,msg);
return;
case PARAM_:
sprintf(msg,"P%d",node->op2.coordnum+1);
print_attr(node,msg);
return;
case PUSHPARAM:
if ( (vch == 'X') && (node->op1.coordnum+1 <= 3) )
sprintf(msg,"%c",'x'+node->op1.coordnum);
else
sprintf(msg,"%c%d",vch,node->op1.coordnum+1);
print_attr(node,msg);
return;
case SET_MMODULUS_:
sprintf(pos,"%s.modulus %s ",METH_INSTANCE(node->op1.meth_id)->name,
assign_symbol(node->op2.assigntype));
pos += strlen(pos);
exprint_recur(node+node->left,prec_parent);
break;
case SET_QMODULUS_:
sprintf(pos,"%s.modulus %s ",GEN_QUANT(node->op1.quant_id)->name,
assign_symbol(node->op2.assigntype));
pos += strlen(pos);
exprint_recur(node+node->left,prec_parent);
break;
case SET_QTARGET_:
sprintf(pos,"%s.target %s ",GEN_QUANT(node->op1.quant_id)->name,
assign_symbol(node->op2.assigntype));
pos += strlen(pos);
exprint_recur(node+node->left,prec_parent);
break;
case SET_QVOLCONST_:
sprintf(pos,"%s.volconst %s ",GEN_QUANT(node->op1.quant_id)->name,
assign_symbol(node->op2.assigntype));
pos += strlen(pos);
exprint_recur(node+node->left,prec_parent);
break;
case SET_QTOLERANCE_:
sprintf(pos,"%s.tolerance %s ",GEN_QUANT(node->op1.quant_id)->name,
assign_symbol(node->op2.assigntype));
pos += strlen(pos);
exprint_recur(node+node->left,prec_parent);
break;
case PUSHQFIXED_:
sprintf(pos,"%s.fixed",GEN_QUANT(node->op1.quant_id)->name);
pos += strlen(pos);
return;
case PUSHQENERGY_:
sprintf(pos,"%s.energy",GEN_QUANT(node->op1.quant_id)->name);
pos += strlen(pos);
return;
case PUSHQINFO_ONLY_:
sprintf(pos,"%s.info_only",GEN_QUANT(node->op1.quant_id)->name);
pos += strlen(pos);
return;
case PUSHQCONSERVED_:
sprintf(pos,"%s.conserved",GEN_QUANT(node->op1.quant_id)->name);
pos += strlen(pos);
return;
case PUSHQPRESSURE_:
sprintf(pos,"%s.pressure",GEN_QUANT(node->op1.quant_id)->name);
pos += strlen(pos);
return;
case PUSHQTARGET_:
sprintf(pos,"%s.target",GEN_QUANT(node->op1.quant_id)->name);
pos += strlen(pos);
return;
case PUSHMVALUE_:
sprintf(pos,"%s.value",METH_INSTANCE(node->op1.meth_id)->name);
pos += strlen(pos);
return;
case PUSHQVALUE_:
sprintf(pos,"%s.value",GEN_QUANT(node->op1.quant_id)->name);
pos += strlen(pos);
return;
case PUSHMMODULUS_:
sprintf(pos,"%s.modulus",GEN_QUANT(node->op1.meth_id)->name);
pos += strlen(pos);
return;
case PUSHQMODULUS_:
sprintf(pos,"%s.modulus",GEN_QUANT(node->op1.quant_id)->name);
pos += strlen(pos);
return;
case PUSHQVOLCONST_:
sprintf(pos,"%s.volconst",globals(node->op1.quant_id)->name);
pos += strlen(pos);
return;
case PUSHDELTA_:
sprintf(pos,"%s.pdelta",globals(node->op1.name_id)->name);
pos += strlen(pos);
return;
case PUSH_PARAM_SCALE:
sprintf(pos,"%s.pscale",globals(node->op1.name_id)->name);
pos += strlen(pos);
return;
case PUSH_PARAM_FIXED:
sprintf(pos,"%s.fixed",globals(node->op1.name_id)->name);
pos += strlen(pos);
return;
case PUSH_PARAM_EXTRA_:
sprintf(pos,"%s.%s",globals(node->op1.name_id)->name,
EXTRAS(0)[node->op2.extranum].name);
pos += strlen(pos);
return;
case ELEMENT_IDENT_:
{ struct global *g = globals(node->op3.name_id);
sprintf(pos,"%s",g->name);
pos += strlen(pos);
return;
}
case PUSHGLOBAL_:
case STRINGGLOBAL_:
{ struct global *g = globals(node->op1.name_id);
if ( g->flags & QUANTITY_NAME )
sprintf(pos,"total %s",g->name);
else sprintf(pos,"%s",g->name);
pos += strlen(pos);
return;
}
case PUSH_PERM_GLOBAL_:
case PERM_STRINGGLOBAL_:
sprintf(pos,"%s",perm_globals(node->op1.name_id)->name);
pos += strlen(pos);
return;
case USERFUNC:
sprintf(pos,"usr%d",node->op1.userfunc+1);
pos += strlen(pos);
return;
case DYNAMIC_LOAD_FUNC_:
sprintf(pos,globals(node->op2.name_id)->name);
pos += strlen(pos);
return;
case PLUS:
binary_print(node,prec_parent,PREC_ADD," + ",PREC_ADD);
return;
case MINUS:
binary_print(node,prec_parent,PREC_SUB," - ",PREC_SUB+1);
return;
case EQUATE:
binary_print(node,prec_parent,PREC_ASSIGN," = ",PREC_ASSIGN+1);
return;
case TIMES:
binary_print(node,prec_parent,PREC_MUL,"*",PREC_MUL);
return;
case DIVIDE:
binary_print(node,prec_parent,PREC_DIV,"/",PREC_DIV+1);
return;
case REALMOD:
binary_print(node,prec_parent,PREC_DIV,"%%",PREC_DIV+1);
return;
case IMOD_:
binary_print(node,prec_parent,PREC_DIV," imod ",PREC_DIV+1);
return;
case IDIV_:
binary_print(node,prec_parent,PREC_DIV," idiv ",PREC_DIV+1);
return;
case COND_ELSE_:
binary_print(node,prec_parent,PREC_COND,"):(",PREC_COND);
strcat(pos++,")");
return;
case COND_EXPR_:
strcat(pos++,"(");
binary_print(node,prec_parent,PREC_COND,")?(",PREC_COND);
return;
case COND_TEST_:
exprint_recur(node+node->left,PREC_COND);
return;
case INV:
exprint_recur(node+node->left,PREC_POW);
sprintf(pos,"^(-1)");
pos += strlen(pos);
return;
case INTPOW:
exprint_recur(node+node->left,PREC_POW);
sprintf(pos,"^%1d",node->op1.intpow);
pos += strlen(pos);
return;
case POW:
binary_print(node,prec_parent,PREC_POW,"**",PREC_POW);
return;
case MAXIMUM_:
strcat(pos,"maximum(");
pos += strlen(pos);
exprint_recur(node+node->left,PREC_ARG);
strcat(pos++,",");
exprint_recur(node+node->right,PREC_ARG);
strcat(pos++,")");
return;
case MINIMUM_:
strcat(pos,"minimum(");
pos += strlen(pos);
exprint_recur(node+node->left,PREC_ARG);
strcat(pos++,",");
exprint_recur(node+node->right,PREC_ARG);
strcat(pos++,")");
return;
case INCOMPLETE_ELLIPTICF:
sprintf(pos,"incompleteEllipticF(");
pos += strlen(pos);
exprint_recur(node+node->left,PREC_ARG);
strcat(pos++,",");
exprint_recur(node+node->right,PREC_ARG);
strcat(pos++,")");
return;
case INCOMPLETE_ELLIPTICE:
sprintf(pos,"incompleteEllipticE(");
pos += strlen(pos);
exprint_recur(node+node->left,PREC_ARG);
strcat(pos++,",");
exprint_recur(node+node->right,PREC_ARG);
strcat(pos++,")");
return;
case ATAN2_:
sprintf(pos,"atan2(");
pos += strlen(pos);
exprint_recur(node+node->left,PREC_ARG);
strcat(pos++,",");
exprint_recur(node+node->right,PREC_ARG);
strcat(pos++,")");
return;
case WRAP_COMPOSE_:
sprintf(pos,"wrap_compose(");
pos += strlen(pos);
exprint_recur(node+node->left,PREC_ARG);
strcat(pos++,",");
exprint_recur(node+node->right,PREC_ARG);
strcat(pos++,")");
return;
case WRAP_INVERSE_:
sprintf(pos,"wrap_inverse(");
pos += strlen(pos);
exprint_recur(node+node->left,PREC_ARG);
sprintf(pos,")");
pos += strlen(pos);
return;
case SQR:
sprintf(pos,"(");
pos += strlen(pos);
exprint_recur(node+node->left,PREC_ARG);
sprintf(pos,")^2");
pos += strlen(pos);
return;
case SQRT:
sprintf(pos,"sqrt(");
pos += strlen(pos);
exprint_recur(node+node->left,PREC_ARG);
sprintf(pos,")");
pos += strlen(pos);
return;
case FLOOR_:
sprintf(pos,"floor(");
pos += strlen(pos);
exprint_recur(node+node->left,PREC_ARG);
sprintf(pos,")");
pos += strlen(pos);
return;
case CEIL_:
sprintf(pos,"ceil(");
pos += strlen(pos);
exprint_recur(node+node->left,PREC_ARG);
sprintf(pos,")");
pos += strlen(pos);
return;
case ABS:
sprintf(pos,"abs(");
pos += strlen(pos);
exprint_recur(node+node->left,PREC_ARG);
sprintf(pos,")");
pos += strlen(pos);
return;
case SINH:
sprintf(pos,"sinh(");
pos += strlen(pos);
exprint_recur(node+node->left,PREC_ARG);
sprintf(pos,")");
pos += strlen(pos);
return;
case COSH:
sprintf(pos,"cosh(");
pos += strlen(pos);
exprint_recur(node+node->left,PREC_ARG);
sprintf(pos,")");
pos += strlen(pos);
return;
case TANH:
sprintf(pos,"tanh(");
pos += strlen(pos);
exprint_recur(node+node->left,PREC_ARG);
sprintf(pos,")");
pos += strlen(pos);
return;
case ACOSH:
sprintf(pos,"acosh(");
pos += strlen(pos);
exprint_recur(node+node->left,PREC_ARG);
sprintf(pos,")");
pos += strlen(pos);
return;
case ASINH:
sprintf(pos,"asinh(");
pos += strlen(pos);
exprint_recur(node+node->left,PREC_ARG);
sprintf(pos,")");
pos += strlen(pos);
return;
case ATANH:
sprintf(pos,"atanh(");
pos += strlen(pos);
exprint_recur(node+node->left,PREC_ARG);
sprintf(pos,")");
pos += strlen(pos);
return;
case SIN:
sprintf(pos,"sin(");
pos += strlen(pos);
exprint_recur(node+node->left,PREC_ARG);
sprintf(pos,")");
pos += strlen(pos);
return;
case COS:
sprintf(pos,"cos(");
pos += strlen(pos);
exprint_recur(node+node->left,PREC_ARG);
sprintf(pos,")");
pos += strlen(pos);
return;
case TAN:
sprintf(pos,"tan(");
pos += strlen(pos);
exprint_recur(node+node->left,PREC_ARG);
sprintf(pos,")");
pos += strlen(pos);
return;
case EXP:
sprintf(pos,"exp(");
pos += strlen(pos);
exprint_recur(node+node->left,PREC_ARG);
sprintf(pos,")");
pos += strlen(pos);
return;
case LOG:
sprintf(pos,"log(");
pos += strlen(pos);
exprint_recur(node+node->left,PREC_ARG);
sprintf(pos,")");
pos += strlen(pos);
return;
case ASIN:
sprintf(pos,"asin(");
pos += strlen(pos);
exprint_recur(node+node->left,PREC_ARG);
sprintf(pos,")");
pos += strlen(pos);
return;
case ACOS:
sprintf(pos,"acos(");
pos += strlen(pos);
exprint_recur(node+node->left,PREC_ARG);
sprintf(pos,")");
pos += strlen(pos);
return;
case ATAN:
sprintf(pos,"atan(");
pos += strlen(pos);
exprint_recur(node+node->left,PREC_ARG);
sprintf(pos,")");
pos += strlen(pos);
return;
case ELLIPTICK:
sprintf(pos,"ellipticK(");
pos += strlen(pos);
exprint_recur(node+node->left,PREC_ARG);
sprintf(pos,")");
pos += strlen(pos);
return;
case ELLIPTICE:
sprintf(pos,"ellipticE(");
pos += strlen(pos);
exprint_recur(node+node->left,PREC_ARG);
sprintf(pos,")");
pos += strlen(pos);
return;
case CHS:
sprintf(pos,"-");
pos += strlen(pos);
exprint_recur(node+node->left,PREC_UMINUS);
return;
case NOT_:
sprintf(pos," not ");
pos += strlen(pos);
exprint_recur(node+node->left,PREC_NOT);
return;
case VIEW_MATRIX_:
sprintf(pos,"view_matrix[");
pos += strlen(pos);
exprint_recur(node+node->left,PREC_ARG);
strcat(pos,"]["); pos += 2;
exprint_recur(node+node->right,PREC_ARG);
strcat(pos++,"]");
return;
case LENGTH_:
case VALENCE_:
case AREA_:
case VOLUME_:
case DENSITY_:
case PHASE_:
case ID_:
case STAR_:
case OID_:
case TAG_:
case ORIGINAL_:
case FIXED_:
case NO_REFINE_:
case HIT_PARTNER_:
case NONCONTENT_:
case NODISPLAY_:
case BARE_:
case SQ_MEAN_CURV_:
sprintf(pos," %s ",keywordname(node->type));
pos += strlen(pos);
return;
case GET_EXTRA_ATTR_:
ex = EXTRAS(node->op2.eltype) + node->op3.extranum;
print_attr(node,ex->name);
if ( node->left )
exprint_recur(node+node->left,prec_parent);
break;
case ON_QUANTITY_:
print_attr(node,"on_quantity ");
strcat(pos,GEN_QUANT(node->op2.quant_id)->name);
pos += strlen(pos);
return;
case ON_METHOD_INSTANCE_:
print_attr(node,"on_method_instance ");
strcat(pos,METH_INSTANCE(node->op2.meth_id)->name);
pos += strlen(pos);
return;
case ON_CONSTRAINT_:
print_attr(node,"on_constraint ");
exprint_recur(node+node->left,prec_parent);
return;
case ON_CONSTRAINT_NAME:
print_attr(node,"on_constraint ");
strcat(pos,get_constraint(node->op3.connum)->name);
pos += strlen(pos);
return;
case HIT_CONSTRAINT_:
print_attr(node,"hit_constraint ");
exprint_recur(node+node->left,prec_parent);
return;
case HIT_CONSTRAINT_NAME:
print_attr(node,"hit_constraint ");
strcat(pos,get_constraint(node->op3.connum)->name);
pos += strlen(pos);
return;
case ON_BOUNDARY_:
print_attr(node,"on_boundary ");
exprint_recur(node+node->left,prec_parent);
return;
case ON_BOUNDARY_NAME:
print_attr(node,"on_boundary ");
strcat(pos,web.boundaries[node->op3.bdrynum].name);
pos += strlen(pos);
return;
case QUALIFIED_ATTRIBUTE:
exprint_recur(node+node->left,prec_parent);
strcat(pos,"."); pos++;
exprint_recur(node+node->right,prec_parent);
return;
case GET_MIDV_:
print_attr(node,"midv");
return;
case GET_TRIPLE_PT_:
print_attr(node,"triple_point");
return;
case GET_TETRA_PT_:
print_attr(node,"tetra_point");
return;
case GET_AXIAL_POINT_:
print_attr(node,"axial_point");
return;
case GET_FIXED_:
print_attr(node,"fixed");
return;
case GET_BARE_:
print_attr(node,"bare");
return;
case GET_NO_DISPLAY_:
print_attr(node,"no_display");
return;
case GET_NONCONTENT_:
print_attr(node,"noncontent");
return;
case GET_HIT_PARTNER_:
print_attr(node,"hit_partner");
return;
case GET_NO_REFINE_:
print_attr(node,"no_refine");
return;
case GET_ORIGINAL_:
print_attr(node,"original");
return;
case GET_ID_:
print_attr(node,"id");
return;
case GET_STAR_:
print_attr(node,"star");
return;
case GET_OID_:
print_attr(node,"oid");
return;
case GET_VALENCE_:
print_attr(node,"valence");
return;
case GET_COLOR_:
print_attr(node,"color");
return;
case GET_FRONTCOLOR_:
print_attr(node,"frontcolor");
return;
case GET_BACKCOLOR_:
print_attr(node,"backcolor");
return;
case GET_FRONTBODY_:
print_attr(node,"frontbody");
return;
case GET_BACKBODY_:
print_attr(node,"backbody");
return;
case GET_TAG_:
print_attr(node,"tag");
return;
case GET_ORIENTATION_:
print_attr(node,"orientation");
return;
case GET_SHOW_:
print_attr(node,"show");
return;
case GET_LENGTH_:
print_attr(node,"length");
return;
case GET_MEANCURV_:
print_attr(node,"mean_curvature");
return;
case GET_FIXEDVOL_:
print_attr(node,"volfixed");
return;
case GET_MID_EDGE_:
print_attr(node,"mid_edge");
return;
case GET_MID_FACET_:
print_attr(node,"mid_facet");
return;
case GET_WRAP_:
print_attr(node,"wrap");
return;
case GET_SQ_MEAN_CURV_:
print_attr(node,"sqcurve");
return;
case GET_DIHEDRAL_:
print_attr(node,"dihedral");
return;
case GET_AREA_:
print_attr(node,"area");
return;
case GET_VOLUME_:
print_attr(node,"volume");
return;
case GET_VOLCONST_:
print_attr(node,"volconst");
return;
case GET_TARGET_:
print_attr(node,"target");
return;
case GET_MPI_TASK_:
print_attr(node,"mpi_task");
return;
case GET_PRESSURE_:
print_attr(node,"pressure");
return;
case GET_USERATTR_:
print_attr(node,"user_attr");
return;
case GET_DENSITY_:
print_attr(node,"density");
return;
case GET_PHASE_:
print_attr(node,"phase");
return;
case GET_QUANTITY_:
print_attr(node,GEN_QUANT(node->op2.quant_id)->name);
return;
case GET_INSTANCE_:
print_attr(node,METH_INSTANCE(node->op2.meth_id)->name);
return;
case INDEXSET_:
case DIMENSIONSET_:
if ( node->right )
{ exprint_recur(node+node->left,prec_parent);
strcat(pos++,"[");
exprint_recur(node+node->right,prec_parent);
strcat(pos++,"]");
} else
{
strcat(pos++,"[");
exprint_recur(node+node->left,prec_parent);
strcat(pos++,"]");
}
break;
case SET_ATTRIBUTE_:
strcat(pos,"set "); pos += 4;
case SET_ATTRIBUTE_A: /* single element assign */
case SET_ATTRIBUTE_L: /* skip printing set when in set loop */
if ( pos[-1] != '.' ) strcat(pos++," "); /* just to be sure */
switch ( node->op2.attr_kind )
{ case SET_DENSITY_: print_set_attr(node,"density"); break;
case SET_EXTRA_ATTR_:
{ ex = EXTRAS(node->op3.extra_info>>ESHIFT)
+(node->op3.extra_info&0xFF);
print_attr(node,ex->name);
if ( node->right )
exprint_recur(node+node->right,prec_parent);
}
break;
case SET_PHASE_ : print_set_attr(node,"phase"); break;
case SET_WRAP_ : print_set_attr(node,"wrap"); break;
case SET_ORIENTATION_ : print_set_attr(node,"orientation"); break;
case SET_TARGET_: print_set_attr(node,"target"); break;
case SET_VOLCONST_: print_set_attr(node,"volconst"); break;
case SET_PRESSURE_: print_set_attr(node,"pressure"); break;
case SET_OPACITY_: print_set_attr(node,"opacity"); break;
case SET_COLOR_: print_set_attr(node,"color"); break;
case SET_ORIGINAL_: print_set_attr(node,"original"); break;
case SET_FRONTBODY_: print_set_attr(node,"frontbody"); break;
case SET_BACKBODY_: print_set_attr(node,"backbody"); break;
case SET_FRONTCOLOR_: print_attr(node,"frontcolor"); break;
case SET_BACKCOLOR_: print_set_attr(node,"backcolor"); break;
case SET_CONSTRAINT_:
{ struct constraint *con;
print_set_attr(node,"constraint ");
if ( node[node->left].type == PUSHCONST )
{ int cnum = (int)(node[node->left].op1.real);
con = get_constraint(cnum);
if ( (cnum <= web.maxcon) && (con->attr & NAMED_THING) )
{ strcat(pos,con->name);
pos += strlen(pos);
return;
} /* else recursion takes care of expression number constant */
}
pos += strlen(pos);
break;
}
case SET_BOUNDARY_:
{ struct boundary *bdry;
print_set_attr(node,"boundary ");
if ( node[node->left].type == PUSHCONST )
{ int bnum = (int)(node[node->left].op1.real);
bdry = web.boundaries+bnum;
if ( (bnum <= web.bdrymax) && (bdry->attr & NAMED_THING) )
{ strcat(pos,bdry->name);
pos += strlen(pos);
return;
} /* else recursion takes care of expression number constant */
}
pos += strlen(pos);
break;
}
case SET_TAG_: print_set_attr(node,"tag"); break;
case SET_FIXED_: print_set_attr(node,"fixed"); break;
case SET_BARE_: print_set_attr(node,"bare"); break;
case SET_NO_REFINE_: print_set_attr(node,"no_refine"); break;
case SET_HIT_PARTNER_: print_set_attr(node,"hit_partner"); break;
case SET_NONCONTENT_: print_set_attr(node,"noncontent"); break;
case SET_NO_DISPLAY_: print_set_attr(node,"no_display"); break;
case SET_TETRA_PT_: print_set_attr(node,"tetra_pt"); break;
case SET_AXIAL_POINT_: print_set_attr(node,"axial_point"); break;
case SET_TRIPLE_PT_: print_set_attr(node,"triple_point"); break;
case SET_COORD_1:
if ( node->right )
{ print_set_attr(node,"x");
exprint_recur(node+node->right,prec_parent);
break;
}
else print_set_attr(node,"X1");
break;
case SET_COORD_2: print_set_attr(node,"X2"); break;
case SET_COORD_3: print_set_attr(node,"X3"); break;
case SET_COORD_4: print_set_attr(node,"X4"); break;
case SET_COORD_5: print_set_attr(node,"X5"); break;
case SET_COORD_6: print_set_attr(node,"X6"); break;
case SET_COORD_7: print_set_attr(node,"X7"); break;
case SET_COORD_8: print_set_attr(node,"X8"); break;
case SET_PARAM_1:
if ( node->right )
{ print_set_attr(node,"p1["); pos += 3;
exprint_recur(node+node->right,prec_parent);
strcat(pos,"]"); pos += strlen(pos);
break;
}
else print_set_attr(node,"P1");
break;
case SET_PARAM_2: print_set_attr(node,"P2"); break;
case SET_PARAM_3: print_set_attr(node,"P3"); break;
case SET_PARAM_4: print_set_attr(node,"P4"); break;
default:
sprintf(errmsg,"Internal error: bad SET_ATTRIBUTE type %d.\n",
node->op2.attr_kind);
kb_error(1655,errmsg,RECOVERABLE);
}
if ( node->type == SET_ATTRIBUTE_A )
{ switch ( node[1].op1.assigntype )
{ case ASSIGN_: strcat(pos," := "); break;
case PLUSASSIGN_: strcat(pos," += "); break;
case SUBASSIGN_: strcat(pos," -= "); break;
case MULTASSIGN_: strcat(pos," *= "); break;
case DIVASSIGN_: strcat(pos," /= "); break;
}
pos += 4;
}
strcat(pos," ("); pos += 2;
if ( node->left ) exprint_recur(node+node->left,prec_parent);
strcat(pos++,")");
return;
case SINGLE_ASSIGN_ :
exprint_recur(node+node->left,prec_parent);
*(pos++) = '.'; *pos = 0;
exprint_recur(node+node->right,prec_parent);
return;
case EQ_:
binary_print(node,prec_parent,PREC_COMP," == ",PREC_COMP);
return;
case NE_:
binary_print(node,prec_parent,PREC_COMP," != ",PREC_COMP);
return;
case GE_:
binary_print(node,prec_parent,PREC_COMP," >= ",PREC_COMP);
return;
case LE_:
binary_print(node,prec_parent,PREC_COMP," <= ",PREC_COMP);
return;
case GT_:
binary_print(node,prec_parent,PREC_COMP," > ",PREC_COMP);
return;
case LT_:
binary_print(node,prec_parent,PREC_COMP," < ",PREC_COMP);
return;
case AND_:
binary_print(node,prec_parent,PREC_AND," && ",PREC_AND);
return;
case OR_:
binary_print(node,prec_parent,PREC_OR," || ",PREC_OR);
return;
case CONJUNCTION_END:
exprint_recur(node+node->left,prec_parent);
return;
default:
sprintf(pos,"(unknown)");
pos += strlen(pos);
sprintf(errmsg,"Printing of expression node type %s (%d) unimplemented.\n",
tokname(node->type),node->type);
kb_error(1656,errmsg,WARNING);
return;
}
return ; /* shouldn't happen */
} /* end exprint_recur */
/**************************************************************************
*
* function: binary_print()
*
* purpose: print binary operation with parentheses if needed.
*
*/
void binary_print(node,prec_parent,prec1,op,prec2)
struct treenode *node;
int prec_parent;
int prec1;
char *op;
int prec2;
{
if ( prec_parent > prec1 )
{ sprintf(pos,"(");
pos += strlen(pos);
}
exprint_recur(node+node->left,prec1);
sprintf(pos,op);
pos += strlen(pos);
exprint_recur(node+node->right,prec2);
if ( prec_parent > prec1 )
{ sprintf(pos,")");
pos += strlen(pos);
}
return;
}
/**************************************************************************
*
* function: set_print()
*
* purpose: print SET type command, with possible WHERE clause.
*
*/
void set_print(node,keyw,attrw,prec_parent)
struct treenode *node;
char *keyw,*attrw;
int prec_parent;
{ struct treenode *nnode;
sprintf(pos,"%s ",keyw);
pos += strlen(pos);
nnode = node + node->left;
if ( nnode->type == WHERE_ ) nnode += nnode->left; /* get NEXT_ */
exprint_recur(nnode,prec_parent);
sprintf(pos," %s ",attrw);
pos += strlen(pos);
if ( node->right ) exprint_recur(node+node->right,prec_parent);
if ( node[node->left].type == WHERE_ )
{ node+= node->left;
sprintf(pos," where "); pos += strlen(pos);
exprint_recur(node+node->right,prec_parent);
}
return;
}
void print_attr(node,word)
struct treenode *node;
char *word;
{
sprintf(pos,"%s",word);
pos += strlen(pos); return;
}
void print_set_attr(node,word)
struct treenode *node;
char *word;
{
sprintf(pos,"%s",word);
pos += strlen(pos); return;
}
evolver-2.30c.dfsg/src/grapher.c 0000644 0001753 0001753 00000060506 11410765113 017020 0 ustar hazelsct hazelsct /*************************************************************
* This file is part of the Surface Evolver source code. *
* Programmer: Ken Brakke, brakke@susqu.edu *
*************************************************************/
/*************************************************************
*
* file: grapher.c
*
* contents: Functions for control of interactive
* graphics display.
*/
#include "include.h"
#ifndef TRUE
#define TRUE 1
#define FALSE 0
#endif
#define dang (M_PI/30) /* rotation increment */
static REAL zoomfactor = 1.2; /* scale factor */
static REAL low[MAXCOORD],high[MAXCOORD]; /* extreme coordiates */
static REAL mid[MAXCOORD]; /* midpoint of extremes */
/* matrices */
/* image display motion done via homogeneous coordinates */
static REAL **spinl, **tipup; /* rotation increment matrices */
static REAL **spinr, **tipdown; /* rotation increment matrices */
static REAL **clockwise, **counterclock; /* rotation increment matrices */
static REAL **transleft,**transright; /* translation increment matrices */
static REAL **transup,**transdown; /* translation increment matrices */
static REAL **zoom, **shrink; /* scaling matrices */
static int showflag;
/********************************************************************
*
* function: update_display()
*
* purpose: wrapper for local_update_display()
*/
void update_display()
{
#ifdef MPI_EVOLVER
if ( this_task == 0 )
mpi_update_display();
#endif
local_update_display();
}
/********************************************************************
*
* function: local_update_display()
*
* purpose: Check for necessity of re-displaying surface.
*
*/
void local_update_display()
{
graph_timestamp = ++global_timestamp; /* new surface */
if ( go_display_flag )
{
if ( OOGL_flag ) UpdateOOGL();
else
display();
}
}
/********************************************************************
*
* function: do_show()
*
* purpose: Handles 's' command, displays and switches to
* graphics command mode.
*
*/
void do_show()
{
char line[100]; /* for reading user commands */
int old_flag = iterate_flag;
#ifdef MAC_OS_X
do_show_flag++; /* kludge so mac_exec_commands() does do_show() again */
#endif
#ifndef OPENGL
/* to prevent unnecessary recalculation of display */
graph_timestamp = ++global_timestamp; /* new surface */
#endif
if ( torus_display_mode == TORUS_DEFAULT_MODE ) ask_wrap_display();
/* main loop */
showflag = 1;
do
{
iterate_flag = 2;
if ( showflag ) display();
showflag = 1; /* default to show next time around, unless option
below decides otherwise */
#ifdef MOTIF
return;
#endif
if ( prompt("Graphics command: ",line,sizeof(line)) == EOF ) break;
}
while ( view_transform(line) );
iterate_flag = old_flag;
}
/********************************************************************
*
* function: ask_wrap_display()
*
* purpose: Dialog asking for symmetry group display mode.
*
*/
void ask_wrap_display()
{
if ( commandfd != stdin ) return;
if ( web.torus_flag )
{
char response[100];
if ( web.skel[BODY].count == 0 )
prompt("Display raw facets or clipped cell? (0,2): ",response,sizeof(response));
else
prompt("Display raw facets, connected bodies or clipped cell? (0,1,2): ",
response,sizeof(response));
switch ( response[0] )
{
case '0' : torus_display_mode = TORUS_RAW_MODE;
web.torus_body_flag = 0;
web.torus_clip_flag = 0;
break;
case '1' :
if ( web.skel[BODY].count == 0 )
kb_error(1042,"There are no bodies to display connectedly.\n",
WARNING);
else { web.torus_body_flag = 1;
web.torus_clip_flag = 0;
torus_display_mode = TORUS_CONNECTED_MODE;}
break;
case '2' :
web.torus_body_flag = 0;
web.torus_clip_flag = 1;
torus_display_mode = TORUS_CLIPPED_MODE;
break;
}
}
else if ( web.symmetry_flag )
{
char response[100];
if ( web.skel[BODY].count == 0 )
{ torus_display_mode = TORUS_RAW_MODE; return; }
prompt("Display raw cell or connected bodies? (0,1): ",response,sizeof(response));
switch ( response[0] )
{
case '0' : torus_display_mode = TORUS_RAW_MODE;
web.torus_body_flag = 0;
web.torus_clip_flag = 0;
break;
case '1' :
if ( web.skel[BODY].count == 0 )
kb_error(1043,"There are no bodies to display connectedly.\n",
WARNING);
else { web.torus_body_flag = 1;
web.torus_clip_flag = 0;
torus_display_mode = TORUS_CONNECTED_MODE;}
break;
}
}
}
/********************************************************************
*
* function: view_transform()
*
* purpose: parse and execute "graphics command" input.
*
*/
int view_transform(string)
char *string;
{
char *c;
size_t legal; /* number of legal characters at start of string */
/* test for illegal characters */
legal = strspn(string,
"0123456789.+-udrlcCRmzsABDxqtvwbeETH?h\034\035\036\037\033\133\n\r");
if ( legal != strlen(string) )
{ sprintf(msg,"Illegal character in graphics command: %c",string[legal]);
kb_error(1044,msg,WARNING);
showflag = 0; /* don't reshow */
return 1;
}
for ( c = string ; *c ; c++ )
{ int reps = 1; /* repetition count */
REAL val = 0.0; /* for arbitrary rotations */
int decflag = 0; /* whether have real number for angle or other */
char *cc = c;
if ( isdigit(*c) )
reps = atoi(c);
if ( isdigit(*c) || (*c=='.') || (*c=='-'))
{ val = atof(c);
if ( *cc == '.' ) decflag = 1;
cc = c+1;
while ( isdigit(*cc) || (*cc=='.'))
{ if ( *cc == '.' ) decflag = 1;
cc++;
}
}
if ( decflag ) { reps = 1; c = cc; }
else if ( *c == '-' ) { /* '-' for color decrement */ }
else { c = cc; val = 6.0; /* default angle */ }
while ( reps-- > 0 )
switch ( *c )
{
case 0: return 1;
case 'u':
if ( !decflag ) val = 6.0;
set_tipup(val*M_PI/180);
mat_mult(tipup,view,view,HOMDIM,HOMDIM,HOMDIM); break;
case 'd':
if ( !decflag ) val = 6.0;
set_tipdown(val*M_PI/180);
mat_mult(tipdown,view,view,HOMDIM,HOMDIM,HOMDIM); break;
case 'r':
if ( !decflag ) val = 6.0;
set_spinr(val*M_PI/180);
mat_mult(spinr,view,view,HOMDIM,HOMDIM,HOMDIM); break;
case 'l':
if ( !decflag ) val = 6.0;
set_spinl(val*M_PI/180);
mat_mult(spinl,view,view,HOMDIM,HOMDIM,HOMDIM); break;
case 'c':
if ( !decflag ) val = 6.0;
set_clockwise(val*M_PI/180);
mat_mult(clockwise,view,view,HOMDIM,HOMDIM,HOMDIM);
break;
case 'C':
if ( !decflag ) val = 6.0;
set_counterclockwise(val*M_PI/180);
mat_mult(counterclock,view,view,HOMDIM,HOMDIM,HOMDIM);
break;
case 'z':
if ( !decflag ) val = 1.2;
set_zoom(val);
mat_mult(zoom ,view,view,HOMDIM,HOMDIM,HOMDIM); break;
case 's':
if ( !decflag ) val = 1.2;
set_zoom(1/val);
mat_mult(zoom,view,view,HOMDIM,HOMDIM,HOMDIM); break;
/* MS-DOS arrow keys for translation */
case 30:
transup[SDIM>2?2:1][HOMDIM-1] = decflag ? val : 0.25;
mat_mult(transup, view,view,HOMDIM,HOMDIM,HOMDIM);
break;
case 31:
transdown[SDIM>2?2:1][HOMDIM-1] = decflag ? -val : -0.25;
mat_mult(transdown,view,view,HOMDIM,HOMDIM,HOMDIM);
break;
case 28:
transright[SDIM>2?1:0][HOMDIM-1] = decflag ? val : 0.25;
mat_mult(transright,view,view,HOMDIM,HOMDIM,HOMDIM);
break;
case 29:
transleft[SDIM>2?1:0][HOMDIM-1] = decflag ? -val : -0.25;
mat_mult(transleft,view,view,HOMDIM,HOMDIM,HOMDIM);
break;
case 0x1b : /* ANSI arrow keys for translation */
if ( *(++c) != 0x5B )
{ if ( isprint(*c) )
sprintf(msg,"Unrecognized character: %c\n",*c);
else sprintf(msg,"Unrecognized character: 0x%04X\n",*c);
outstring(msg);
break;
}
switch ( *(++c) )
{
case 0x41:
transup[SDIM>2?2:1][HOMDIM-1] = decflag ? val : 0.25;
mat_mult(transup, view,view,HOMDIM,HOMDIM,HOMDIM);
break;
case 0x42:
transdown[SDIM>2?2:1][HOMDIM-1] = decflag ? -val : -0.25;
mat_mult(transdown,view,view,HOMDIM,HOMDIM,HOMDIM);
break;
case 0x43:
transright[SDIM>2?1:0][HOMDIM-1] = decflag ? val : 0.25;
mat_mult(transright,view,view,HOMDIM,HOMDIM,HOMDIM);
break;
case 0x44:
transleft[SDIM>2?1:0][HOMDIM-1] = decflag ? -val : -0.25;
mat_mult(transleft,view,view,HOMDIM,HOMDIM,HOMDIM);
break;
default:
if ( isprint(*c) )
sprintf(msg,"Unrecognized character: %c\n",*c);
else sprintf(msg,"Unrecognized character: 0x%04X \n",*c);
outstring(msg);
break;
}
break;
case 'R':
if ( decflag ) /* particular scaling */
{ int i;
matcopy(view,identmat,HOMDIM,HOMDIM);
for ( i = 0 ; i < HOMDIM-1 ; i++ )
{ view[i][i] = val;
}
}
else resize();
reps = 0; graph_timestamp = ++global_timestamp;
break;
case 'm': /* middle, for centering */
{ do_gfile(0,NULL); /* get bounding box */
if ( SDIM == 2 )
{ view[0][HOMDIM-1] -= (bbox_maxx+bbox_minx)/2;
view[1][HOMDIM-1] -= (bbox_maxy+bbox_miny)/2;
} else
{ view[1][HOMDIM-1] -= (bbox_maxx+bbox_minx)/2;
view[2][HOMDIM-1] -= (bbox_maxy+bbox_miny)/2;
}
break;
}
case 'x':
case 'q': return 0;
case 't':
if ( !web.symmetry_flag ) break;
ask_wrap_display(); graph_timestamp = ++global_timestamp;
reps = 0; break;
case 'B': bdry_showflag = !bdry_showflag;
graph_timestamp = ++global_timestamp;
reps = 0; break;
case 'v': ridge_color_flag = !ridge_color_flag; reps = 0;
graph_timestamp = ++global_timestamp;break;
case 'w': no_wall_flag = !no_wall_flag; reps = 0;
graph_timestamp = ++global_timestamp;break;
case 'b': box_flag = !box_flag; reps = 0;
graph_timestamp = ++global_timestamp; break;
case 'e': edgeshow_flag = !edgeshow_flag;
graph_timestamp = ++global_timestamp; break;
case 'E': triple_edgeshow_flag = !triple_edgeshow_flag;
graph_timestamp = ++global_timestamp; break;
case 'T': transforms_flag = !transforms_flag;
graph_timestamp = ++global_timestamp; break;
case '+': fillcolor++;
sprintf(msg,"fillcolor %d\n",fillcolor);
outstring(msg);
graph_timestamp = ++global_timestamp;
reps = 0; break;
case '-': fillcolor--;
sprintf(msg,"fillcolor %d\n",fillcolor);
outstring(msg);
graph_timestamp = ++global_timestamp;
reps = 0; break;
case 'H': web.hide_flag = !web.hide_flag; reps = 0;
graph_timestamp = ++global_timestamp;
break;
case '?':
case 'h':
graph_help();
showflag = 0;
reps = 0; break;
case '\n': case '\r': break;
default:
if ( isprint(*c) )
sprintf(msg,"Unrecognized letter: %c\n",*c);
else sprintf(msg,"Unrecognized character: 0x%04x \n",*c);
outstring(msg);
reps = 0; showflag = 0;
break;
}
}
return 1;
} /* end view_transform() */
/********************************************************************
*
* function: init_view()
*
* purpose: Initialize viewing and transform matrices.
*
*/
void init_view()
{
int i;
view = dmatrix(0,SDIM,0,SDIM);
if ( identmat == NULL )
{ /* first time set-up */
/* set up identity matrix */
identmat = perm_matrix2(MAXCOORD+1,MAXCOORD+1);
for ( i = 0 ; i <= MAXCOORD ; i++ )
identmat[i][i] = 1.0;
to_focus = perm_matrix2(MAXCOORD+1,MAXCOORD+1);
from_focus = perm_matrix2(MAXCOORD+1,MAXCOORD+1);
/* set rotation matrices */
spinr = perm_matrix2(MAXCOORD+1,MAXCOORD+1);
matcopy(spinr,identmat,SDIM+1,SDIM+1);
spinr[0][0] = spinr[1][1] = cos(dang);
spinr[0][1] = -(spinr[1][0] = sin(dang));
spinl = perm_matrix2(MAXCOORD+1,MAXCOORD+1);
matcopy(spinl,identmat,SDIM+1,SDIM+1);
spinl[0][0] = spinl[1][1] = cos(dang);
spinl[0][1] = -(spinl[1][0] = -sin(dang));
tipup = perm_matrix2(MAXCOORD+1,MAXCOORD+1);
matcopy(tipup,identmat,SDIM+1,SDIM+1);
tipup[0][0] = tipup[2][2] = cos(dang);
tipup[0][2] = -(tipup[2][0] = sin(dang));
tipdown = perm_matrix2(MAXCOORD+1,MAXCOORD+1);
matcopy(tipdown,identmat,SDIM+1,SDIM+1);
tipdown[0][0] = tipdown[2][2] = cos(dang);
tipdown[0][2] = -(tipdown[2][0] = -sin(dang));
clockwise = perm_matrix2(MAXCOORD+1,MAXCOORD+1);
matcopy(clockwise,identmat,SDIM+1,SDIM+1);
clockwise[1][1] = clockwise[2][2] = cos(dang);
clockwise[1][2] = -(clockwise[2][1] = -sin(dang));
counterclock = perm_matrix2(MAXCOORD+1,MAXCOORD+1);
matcopy(counterclock,identmat,SDIM+1,SDIM+1);
counterclock[1][1] = counterclock[2][2] = cos(dang);
counterclock[1][2] = -(counterclock[2][1] = sin(dang));
/* set magnifying matrix */
zoom = perm_matrix2(MAXCOORD+1,MAXCOORD+1);
matcopy(zoom,identmat,SDIM+1,SDIM+1);
zoom[0][0] = zoom[1][1] = zoom[2][2] = zoomfactor;
/* set shrink matrix */
shrink = perm_matrix2(MAXCOORD+1,MAXCOORD+1);
matcopy(shrink,identmat,SDIM+1,SDIM+1);
shrink[0][0] = shrink[1][1] = shrink[2][2] = 1/zoomfactor;
/* set translation matrices */
transleft = perm_matrix2(MAXCOORD+1,MAXCOORD+1);
transup = perm_matrix2(MAXCOORD+1,MAXCOORD+1);
transright = perm_matrix2(MAXCOORD+1,MAXCOORD+1);
transdown = perm_matrix2(MAXCOORD+1,MAXCOORD+1);
}
set_view_matrix_global();
matcopy(to_focus,identmat,SDIM+1,SDIM+1);
matcopy(from_focus,identmat,SDIM+1,SDIM+1);
}
/********************************************************************
*
* functions: set_*()
*
* purpose: set key entries of transform matrices.
*
*/
void set_spinr(val)
REAL val;
{
spinr[0][0] = spinr[1][1] = cos(val);
spinr[0][1] = -(spinr[1][0] = sin(val));
}
void set_spinl(val)
REAL val;
{
spinl[0][0] = spinl[1][1] = cos(val);
spinl[0][1] = -(spinl[1][0] = -sin(val));
}
void set_tipup(val)
REAL val;
{
tipup[0][0] = tipup[2][2] = cos(val);
tipup[0][2] = -(tipup[2][0] = sin(val));
}
void set_tipdown(val)
REAL val;
{
tipdown[0][0] = tipdown[2][2] = cos(val);
tipdown[0][2] = -(tipdown[2][0] = -sin(val));
}
void set_clockwise(val)
REAL val;
{
clockwise[1][1] = clockwise[2][2] = cos(val);
clockwise[1][2] = -(clockwise[2][1] = -sin(val));
}
void set_counterclockwise(val)
REAL val;
{
counterclock[1][1] = counterclock[2][2] = cos(val);
counterclock[1][2] = -(counterclock[2][1] = sin(val));
}
void set_zoom(val)
REAL val;
{ zoom[0][0] = zoom[1][1] = val;
if ( web.sdim >= 3 )
zoom[2][2] = val;
}
/********************************************************************
*
* function: reset_view()
*
* purpose: re-initialize view matrix.
*
*/
void reset_view()
{
HOMDIM = web.sdim + 1;
matcopy(transleft,identmat,HOMDIM,HOMDIM);
matcopy(transdown,identmat,HOMDIM,HOMDIM);
matcopy(transright,identmat,HOMDIM,HOMDIM);
matcopy(transup,identmat,HOMDIM,HOMDIM);
if ( SDIM > 2 )
{
transright[1][HOMDIM-1] = .25;
transleft[1][HOMDIM-1] = -.25;
transup[2][HOMDIM-1] = .25;
transdown[2][HOMDIM-1] = -.25;
}
else /* show x-y plane */
{
transright[0][HOMDIM-1] = .25;
transleft[0][HOMDIM-1] = -.25;
transup[1][HOMDIM-1] = .25;
transdown[1][HOMDIM-1] = -.25;
shrink[2][2] = 1.0;
zoom[2][2] = 1.0;
}
}
/********************************************************************
*
* function: resize()
*
* purpose: Recalculate bounding box of surface.
* Also initializes clip_view and slice_view if empty.
*
*/
void resize()
{
int i,j,k;
vertex_id v_id;
REAL size;
/* if domain is torus, get torus fundamental cell in view */
if ( web.torus_flag )
{
for ( i = 0 ; i < SDIM ; i++ ) /* coordinate loop */
{
low[i] = high[i] = 0.0;
for ( j = 0 ; j < SDIM ; j++ ) /* axis loop */
if ( web.torus_period[j][i] < 0.0 ) low[i] += web.torus_period[j][i];
else high[i] += web.torus_period[j][i];
}
if ( transforms_flag )
{ REAL x[MAXCOORD+1];
for ( j = 0 ; j < SDIM ; j++ )
{
for ( i = 0 ; i < SDIM ; i++ ) x[i] = web.torus_period[j][i];
x[SDIM] = 1.0;
for ( k = 0 ; k < transform_count ; k++ )
{ REAL xx,newx[MAXCOORD+1];
matvec_mul(view_transforms[k],x,newx,SDIM+1,SDIM+1);
for ( i = 0 ; i < SDIM ; i++ )
{ xx = newx[i]/newx[SDIM]; /* project */
if ( xx < low[i] ) low[i] = xx;
if ( xx > high[i] ) high[i] = xx;
}
}
}
for ( i = 0 ; i < SDIM ; i++ ) x[i] = 0;
x[SDIM] = 1.0;
for ( k = 0 ; k < transform_count ; k++ )
{ REAL xx,newx[MAXCOORD+1];
matvec_mul(view_transforms[k],x,newx,SDIM+1,SDIM+1);
for ( i = 0 ; i < SDIM ; i++ )
{ xx = newx[i]/newx[SDIM]; /* project */
if ( xx < low[i] ) low[i] = xx;
if ( xx > high[i] ) high[i] = xx;
}
}
}
}
else if ( web.symmetry_flag )
{ edge_id e_id;
for ( i = 0 ; i < SDIM ; i++ ) /* initialize */
{ low[i] = 1e30;
high[i] = -1e30;
}
/* figure out how big window should be */
FOR_ALL_EDGES(e_id)
{ REAL *t;
REAL x[MAXCOORD+1],y[MAXCOORD+1];
t = get_coord(get_edge_tailv(e_id));
for ( i = 0 ; i < SDIM ; i++ ) x[i] = t[i];
(*sym_wrap)(get_coord(get_edge_headv(e_id)),y,get_edge_wrap(e_id));
x[SDIM] = y[SDIM] = 1.0; /* homogeneous coord */
for ( i = 0 ; i < SDIM ; i++ )
{ if ( x[i] < low[i] ) low[i] = x[i];
if ( x[i] > high[i] ) high[i] = x[i];
if ( y[i] < low[i] ) low[i] = y[i];
if ( y[i] > high[i] ) high[i] = y[i];
}
if ( transforms_flag )
for ( j = 0 ; j < transform_count ; j++ )
{ REAL xx,newx[MAXCOORD+1];
matvec_mul(view_transforms[j],x,newx,SDIM+1,SDIM+1);
for ( i = 0 ; i < SDIM ; i++ )
{ xx = newx[i]/newx[SDIM]; /* project */
if ( xx < low[i] ) low[i] = xx;
if ( xx > high[i] ) high[i] = xx;
}
matvec_mul(view_transforms[j],y,newx,SDIM+1,SDIM+1);
for ( i = 0 ; i < SDIM ; i++ )
{ xx = newx[i]/newx[SDIM]; /* project */
if ( xx < low[i] ) low[i] = xx;
if ( xx > high[i] ) high[i] = xx;
}
}
}
}
else
{
for ( i = 0 ; i < SDIM ; i++ ) /* initialize */
{ low[i] = 1e30;
high[i] = -1e30;
}
/* figure out how big window should be */
FOR_ALL_VERTICES(v_id)
{ REAL *x = get_coord(v_id);
if ( transform_count && transforms_flag )
{ REAL y[MAXCOORD+1];
for ( i = 0 ; i < SDIM ; i++ ) y[i] = x[i];
y[SDIM] = 1.0; /* homogeneous coord */
for ( j = 0 ; j < transform_count ; j++ )
{ REAL xx,newx[MAXCOORD+1];
matvec_mul(view_transforms[j],y,newx,SDIM+1,SDIM+1);
if ( fabs(newx[SDIM]) < 1e-12 )
{ sprintf(errmsg,"View transform matrix %d is singular.\n",j+1);
kb_error(1045,errmsg,WARNING);
}
else
for ( i = 0 ; i < SDIM ; i++ )
{ xx = newx[i]/newx[SDIM];;
if ( xx < low[i] ) low[i] = xx;
if ( xx > high[i] ) high[i] = xx;
}
}
} /* end transforms */
else /* just plain vertices */
for ( i = 0 ; i < SDIM ; i++ )
{ if ( x[i] < low[i] ) low[i] = x[i];
if ( x[i] > high[i] ) high[i] = x[i];
}
}
}
for ( i = 0 ; i < SDIM ; i++ ) mid[i] = (low[i] + high[i])/2;
size = high[2] - low[2];
if ( high[1] - low[1] > size ) size = high[1] - low[1];
if ( high[0] - low[0] > size ) size = high[0] - low[0];
/* transformation matrix will be set up to scale object into
[-1,1]^3 cube */
matcopy(view,identmat,HOMDIM,HOMDIM);
if ( size != 0.0 )
for ( i = 0 ; i < HOMDIM-1 ; i++ )
{ view[i][i] = 2/size;
view[i][HOMDIM-1] = -mid[i]*2/size;
}
if ( to_focus ) /* for oglgraph.c focus reset */
{ matcopy(to_focus,identmat,HOMDIM,HOMDIM);
matcopy(from_focus,identmat,HOMDIM,HOMDIM);
}
/* see if clip_view and slice_view need defaults */
if ( (clip_coeff[0][0] == 0.0) &&
(clip_coeff[0][1] == 0.0) &&
(clip_coeff[0][2] == 0.0))
{ clip_coeff[0][0] = 1.0;
clip_coeff[0][3] = mid[0];
}
if ( (slice_coeff[0] == 0.0) &&
(slice_coeff[1] == 0.0) &&
(slice_coeff[2] == 0.0))
{ slice_coeff[0] = 1.0;
slice_coeff[3] = mid[0];
}
overall_size = size; /* for anybody who wants to know how big */
if ( !user_thickness_flag ) thickness = 0.001*size;
}
/********************************************************************
*
* function: fix_ctm()
*
* Rotates coordinate transformation matrix according to how mouse
* dragged.
*/
void fix_ctm(viewmat,dx,dy)
REAL **viewmat; /* matrix to modify */
REAL dx,dy; /* pixels mouse dragged */
{
MAT2D(rot,MAXCOORD+1,MAXCOORD+1);
REAL alpha; /* angle around axis */
REAL theta; /* tilt of rotation axis */
int i,j;
for ( i = 0 ; i < HOMDIM ; i++ )
{ for ( j = 0 ; j < HOMDIM ; j++ )
rot[i][j] = 0.0;
rot[i][i] = 1.0;
}
alpha = sqrt(dx*dx + dy*dy)/300; /* one radian per 300 pixels */
if ( dx == 0.0 )
{ if ( dy > 0.0 ) theta = M_PI/2;
else if ( dy < 0.0 ) theta = -M_PI/2;
else goto ctm_exit; /* no change */
}
else
{ theta = atan(dy/dx);
if ( dx < 0.0 ) alpha = - alpha;
}
if ( SDIM == 2 )
{
/* tilt axis */
rot[2][2] = 1.0;
rot[0][0] = rot[1][1] = cos(theta);
rot[0][1] = sin(theta);
rot[1][0] = -sin(theta);
mat_mult(rot,viewmat,viewmat,HOMDIM,HOMDIM,HOMDIM);
/* rotate */
rot[2][2] = rot[0][0] = cos(alpha);
rot[2][0] = -sin(alpha);
rot[0][2] = sin(alpha);
rot[1][1] = 1.0;
rot[0][1] = rot[1][0] = 0.0;
mat_mult(rot,viewmat,viewmat,HOMDIM,HOMDIM,HOMDIM);
/* untilt axis */
rot[2][2] = 1.0;
rot[0][0] = rot[1][1] = cos(theta);
rot[0][1] = -sin(theta);
rot[1][0] = sin(theta);
rot[2][0] = rot[0][2] = 0.0;
}
else
{
/* tilt axis */
rot[0][0] = 1.0;
rot[1][1] = rot[2][2] = cos(theta);
rot[1][2] = sin(theta);
rot[2][1] = -sin(theta);
mat_mult(rot,viewmat,viewmat,HOMDIM,HOMDIM,HOMDIM);
/* rotate */
rot[0][0] = rot[1][1] = cos(alpha);
rot[0][1] = -sin(alpha);
rot[1][0] = sin(alpha);
rot[2][2] = 1.0;
rot[1][2] = rot[2][1] = 0.0;
mat_mult(rot,viewmat,viewmat,HOMDIM,HOMDIM,HOMDIM);
/* untilt axis */
rot[0][0] = 1.0;
rot[1][1] = rot[2][2] = cos(theta);
rot[1][2] = -sin(theta);
rot[2][1] = sin(theta);
rot[0][1] = rot[1][0] = 0.0;
}
mat_mult(rot,viewmat,viewmat,HOMDIM,HOMDIM,HOMDIM);
ctm_exit: ;
} /* end fix_ctm() */
evolver-2.30c.dfsg/src/method5.c 0000644 0001753 0001753 00000153625 11410765113 016742 0 ustar hazelsct hazelsct /*************************************************************
* This file is part of the Surface Evolver source code. *
* Programmer: Ken Brakke, brakke@susqu.edu *
* *
* Code for SVK and Neo_hookean submitted by *
* Dr. Rabah Bouzidi *
* Institut de Recherche en Gnie Civil et Mcanique *
* (Civil Engineering and Mechanical Research Institut) *
* Nantes University *
* France *
* Tl : +33 2 51 12 55 23 *
* rabah.bouzidi@physique.univ-nantes.fr *
*************************************************************/
#include "include.h"
REAL LambertW ARGS((REAL));
/************************************************************************
Named method: SVK (Saint-Venant - Kirchhoff) potential
Psi = lambda/2*(tr(E))^2+mu*(E:E) - (3 lambda + 2 mu) * alpha*(theta)*tr(E)
with E=(C-I)/2 the Green-Lagrange Strain tensor
theta = T-T0 : temperture variation
alpha : thermal dilation coefficient
Written by Dr. Rabah Bouzidi
************************************************************************/
#define LAMBDA_NAME "SVK_lambda"
#define MU_NAME "SVK_mu"
#define ALPHA_NAME "SVK_alpha"
#define THETA_NAME "SVK_theta"
#define FORM_FACTORS_NAME "form_factors"
static int lambda_attr; /* number of lambda extra attribute */
static int mu_attr; /* number of mu extra attribute */
static int alpha_attr ; /* number of alpha extra attribute */
static int theta_attr ; /* number of theta extra attribute */
extern int form_factors_attr; /* number of form_factors extra attribute */
/***************************************************************
*
* function: SVK_init()
*
* purpose: Make sure needed extra attributes are present.
*
*/
void SVK_init(mode,mi)
int mode; /* energy or gradient */
struct method_instance *mi;
{
if ( web.modeltype != LINEAR )
kb_error(2811,"Saint-Veant - Kirchhoff method only for LINEAR model.\n",RECOVERABLE);
if ( web.dimension != 2 )
kb_error(2812,"Saint-Veant - Kirchhoff method only for SOAPFILM model.\n",
RECOVERABLE);
/* extra edge atribute */
lambda_attr = find_attribute(FACET,LAMBDA_NAME);
if ( lambda_attr < 0 ) /* not found */
kb_error(2813,"Facet extra attribute SVK_lambda missing. Needed by SVK_elastic method.\n",RECOVERABLE);
mu_attr = find_attribute(FACET,MU_NAME);
if ( mu_attr < 0 ) /* not found */
kb_error(2814,"Facet extra attribute SVK_mu missing. Needed by SVK_elastic method.\n",RECOVERABLE);
alpha_attr = find_attribute(FACET,ALPHA_NAME);
if ( alpha_attr < 0 ) /* not found */
kb_error(2815,"Facet extra attribute alpha missing. Needed by Saint-Veant - Kirchhoff.\n",RECOVERABLE);
theta_attr = find_attribute(FACET,THETA_NAME);
if ( theta_attr < 0 ) /* not found */
kb_error(2816,"Facet extra attribute theta missing. Needed by Saint-Veant - Kirchhoff.\n",RECOVERABLE);
form_factors_attr = find_attribute(FACET,FORM_FACTORS_NAME);
if ( form_factors_attr < 0 ) /* not found */
kb_error(2817,"Facet extra attribute form_factors real[3] missing. Needed by Saint-Veant - Kirchhoff.\n",RECOVERABLE);
if ( EXTRAS(FACET)[form_factors_attr].array_spec.datacount != 3 )
kb_error(2818,"Facet extra attribute form_factors must have size 3.\n",
RECOVERABLE);
}
/************************************************************************
*
* function: SVK_all()
*
* purpose: energy, gradient, and hessian for linear_elastic method.
*/
REAL SVK_all ARGS((struct qinfo *,int));
REAL SVK_all(f_info,mode)
struct qinfo *f_info;
int mode; /* METHOD_VALUE, METHOD_GRADIENT, or METHOD_HESSIAN */
{
REAL *s; /* pointer to extra attributes */
REAL **side;
REAL q11,q12,q22; /* Q entries */
REAL det; /* det S */
REAL lambda; /* lambda coefficient */
REAL area; /* reference area of facet (area of facet in initial configuration - undeformed facet)*/
REAL mu; /* mu coefficient */
REAL alpha; /* Thermic dilatation coefficient */
REAL theta ; /* Relative variation of temperture to the the reference state's temperature*/
REAL f11,f12,f22;
REAL c11,c12,c21,c22;
REAL energy;
REAL dc11dv[FACET_VERTS][MAXCOORD];
REAL dc12dv[FACET_VERTS][MAXCOORD];
REAL dc21dv[FACET_VERTS][MAXCOORD];
REAL dc22dv[FACET_VERTS][MAXCOORD];
REAL ddc11dv[FACET_VERTS][MAXCOORD][FACET_VERTS];
REAL ddc12dv[FACET_VERTS][MAXCOORD][FACET_VERTS];
REAL ddc21dv[FACET_VERTS][MAXCOORD][FACET_VERTS];
REAL ddc22dv[FACET_VERTS][MAXCOORD][FACET_VERTS];
/* Potential derivatives */
REAL dpsirdc11,dpsirdc12,dpsirdc21,dpsirdc22;
REAL ddpsirdc11dc11, ddpsirdc11dc12, ddpsirdc11dc21, ddpsirdc11dc22;
REAL ddpsirdc12dc11, ddpsirdc12dc12, ddpsirdc12dc21, ddpsirdc12dc22;
REAL ddpsirdc21dc11, ddpsirdc21dc12, ddpsirdc21dc21, ddpsirdc21dc22;
REAL ddpsirdc22dc11, ddpsirdc22dc12, ddpsirdc22dc21, ddpsirdc22dc22;
int i,j,ii,jj;
lambda = *(REAL*)get_extra(f_info->id,lambda_attr);
mu = *(REAL*)get_extra(f_info->id,mu_attr);
alpha = *(REAL*)get_extra(f_info->id,alpha_attr);
theta = *(REAL*)get_extra(f_info->id,theta_attr);
s = (REAL*)get_extra(f_info->id,form_factors_attr);
det = s[0]*s[2] - s[1]*s[1];
if ( det <= 0.0 )
{
if ( mode == METHOD_VALUE ) return 0.0;
sprintf(errmsg," SVK_elastic: Facet %d has unstrained area 0.\n",
ordinal(f_info->id)+1);
kb_error(2895,errmsg,RECOVERABLE);
}
area = sqrt(det)/2.0;
q11 = s[2]/det; q12 = -s[1]/det; q22 = s[0]/det;
side = f_info->sides[0];
f11 = SDIM_dot(side[0],side[0]);
f12 = SDIM_dot(side[0],side[1]);
f22 = SDIM_dot(side[1],side[1]);
c11 = f11*q11 + f12*q12;
c12 = f11*q12 + f12*q22;
c21 = f12*q11 + f22*q12;
c22 = f12*q12 + f22*q22;
/*
This exression of the potential takes into account the plane stress condition : Sig33 = 0,
This condition leads to the expression of c33, which can be written as a
function of c11 and c22 : c33 = -(lambda*(c11+c22-3)-2*mu)/(lambda+2*mu)
*/
energy =area*((2.0*mu+3.0*lambda)*alpha*theta*(-(2.0*mu+3.0*lambda)*alpha*theta-2.0*mu*(c11+c22-2.0))+((c22*c22+c11*c11+2.0*c12*c21+2.0-2.0*c11-2.0*c22)*mu*mu+(c11*c22+c12*c21+c22*c22+c11*c11+3.0-3.0*c11-3.0*c22)*lambda*mu))/(2.0*lambda+4.0*mu);
if ( mode == METHOD_VALUE ) return energy;
/* gradient */
for ( i = 0 ; i < SDIM ; i++ )
{
dc11dv[1][i] = 2*side[0][i]*q11 + side[1][i]*q12;
dc11dv[2][i] = side[0][i]*q12;
dc12dv[1][i] = 2*side[0][i]*q12 + side[1][i]*q22;
dc12dv[2][i] = side[0][i]*q22;
dc21dv[1][i] = side[1][i]*q11;
dc21dv[2][i] = side[0][i]*q11 + 2*side[1][i]*q12;
dc22dv[1][i] = side[1][i]*q12;
dc22dv[2][i] = side[0][i]*q12 + 2*side[1][i]*q22;
dc11dv[0][i] = -(dc11dv[1][i] + dc11dv[2][i]);
dc12dv[0][i] = -(dc12dv[1][i] + dc12dv[2][i]);
dc21dv[0][i] = -(dc21dv[1][i] + dc21dv[2][i]);
dc22dv[0][i] = -(dc22dv[1][i] + dc22dv[2][i]);
}
dpsirdc11 = mu*((2.0*c11-2.0)*mu+2.0*lambda*c11-3.0*lambda+lambda*c22-4.0*alpha*theta*mu-6.0*alpha*theta*lambda)/(lambda+2.0*mu)/2.0;
dpsirdc12 = mu*c21/2.0;
dpsirdc21 = mu*c12/2.0;
dpsirdc22 = mu*((2.0*c22-2.0)*mu+2.0*lambda*c22-3.0*lambda+lambda*c11-4.0*alpha*theta*mu-6.0*alpha*theta*lambda)/(lambda+2.0*mu)/2.0;
for ( j = 0 ; j < FACET_VERTS ; j++ )
for ( i = 0 ; i < SDIM ; i++ )
{ f_info->grad[j][i] = area*(dpsirdc11*dc11dv[j][i]
+dpsirdc12*dc12dv[j][i]
+dpsirdc21*dc21dv[j][i]
+dpsirdc22*dc22dv[j][i]);
}
if ( mode == METHOD_GRADIENT ) return energy;
/* hessian */
for ( i = 0 ; i < SDIM ; i++ )
{
ddc11dv[1][i][1] = 2*q11;
ddc11dv[1][i][2] = q12;
ddc11dv[2][i][1] = q12;
ddc11dv[2][i][2] = 0.0;
ddc12dv[1][i][1] = 2*q12;
ddc12dv[1][i][2] = q22;
ddc12dv[2][i][1] = q22;
ddc12dv[2][i][2] = 0.0;
ddc21dv[1][i][1] = 0.0;
ddc21dv[1][i][2] = q11;
ddc21dv[2][i][1] = q11;
ddc21dv[2][i][2] = 2*q12;
ddc22dv[1][i][1] = 0.0;
ddc22dv[1][i][2] = q12;
ddc22dv[2][i][1] = q12;
ddc22dv[2][i][2] = 2*q22;
for ( j = 1 ; j < FACET_VERTS; j++ )
{
ddc11dv[0][i][j] = -(ddc11dv[1][i][j] + ddc11dv[2][i][j]);
ddc12dv[0][i][j] = -(ddc12dv[1][i][j] + ddc12dv[2][i][j]);
ddc21dv[0][i][j] = -(ddc21dv[1][i][j] + ddc21dv[2][i][j]);
ddc22dv[0][i][j] = -(ddc22dv[1][i][j] + ddc22dv[2][i][j]);
ddc11dv[j][i][0] = -(ddc11dv[j][i][1] + ddc11dv[j][i][2]);
ddc12dv[j][i][0] = -(ddc12dv[j][i][1] + ddc12dv[j][i][2]);
ddc21dv[j][i][0] = -(ddc21dv[j][i][1] + ddc21dv[j][i][2]);
ddc22dv[j][i][0] = -(ddc22dv[j][i][1] + ddc22dv[j][i][2]);
}
ddc11dv[0][i][0] = -(ddc11dv[1][i][0] + ddc11dv[2][i][0]);
ddc12dv[0][i][0] = -(ddc12dv[1][i][0] + ddc12dv[2][i][0]);
ddc21dv[0][i][0] = -(ddc21dv[1][i][0] + ddc21dv[2][i][0]);
ddc22dv[0][i][0] = -(ddc22dv[1][i][0] + ddc22dv[2][i][0]);
}
ddpsirdc11dc11 = mu*(mu+lambda)/(lambda+2.0*mu);
ddpsirdc11dc12 = 0.0;
ddpsirdc11dc21 = 0.0 ;
ddpsirdc11dc22 = lambda*mu/(2.0*lambda+4.0*mu);
ddpsirdc12dc11 = 0.0;
ddpsirdc12dc12 = 0.0;
ddpsirdc12dc21 = mu/2.0;
ddpsirdc12dc22 = 0.0;
ddpsirdc21dc11 = 0.0;
ddpsirdc21dc12 = mu/2.0;
ddpsirdc21dc21 = 0.0;
ddpsirdc21dc22 = 0.0;
ddpsirdc22dc11 = mu*lambda/(2.0*lambda+4.0*mu);
ddpsirdc22dc12 = 0.0;
ddpsirdc22dc21 = 0.0;
ddpsirdc22dc22 = mu*(mu+lambda)/(lambda+2.0*mu) ;
for ( j = 0 ; j < FACET_VERTS ; j++ )
for ( i = 0 ; i < SDIM ; i++ )
for ( jj = 0 ; jj < FACET_VERTS ; jj++ )
{
f_info->hess[j][jj][i][i] +=
area*(dpsirdc11*ddc11dv[j][i][jj]
+dpsirdc12*ddc21dv[j][i][jj]
+dpsirdc21*ddc12dv[j][i][jj]
+dpsirdc22*ddc22dv[j][i][jj]);
for ( ii = 0 ; ii < SDIM ; ii++ )
f_info->hess[j][jj][i][ii] +=
area*((ddpsirdc11dc11+ddpsirdc12dc11+ddpsirdc21dc11+ddpsirdc22dc11)*dc11dv[j][i]
+(ddpsirdc11dc12+ddpsirdc12dc12+ddpsirdc21dc12+ddpsirdc22dc12)*dc12dv[j][i]
+(ddpsirdc11dc21+ddpsirdc12dc21+ddpsirdc21dc21+ddpsirdc22dc21)*dc21dv[j][i]
+(ddpsirdc11dc22+ddpsirdc12dc22+ddpsirdc21dc22+ddpsirdc22dc22)*dc22dv[j][i]);
}
return energy;
}
/**************************************************************
*
* function: SVK_energy() (Saint-Veant - Kirchhoff potential)
*
* purpose: calculates energy of one facet due to potential
*
* input: info about vertex is in qinfo structure.
*
*/
REAL SVK_energy(f_info)
struct qinfo *f_info;
{
return SVK_all(f_info,METHOD_VALUE);
}
/**************************************************************
*
* function: SVK_gradient()
*
* purpose: calculates gradient of one facet due to potential
*
* input: info about vertex is in qinfo structure.
*
*/
REAL SVK_gradient(f_info)
struct qinfo *f_info;
{
return SVK_all(f_info,METHOD_GRADIENT);
}
/**************************************************************
*
* function: SVK_hessian()
*
* purpose: calculates hessian of one facet due to potential
*
* input: info about vertex is in qinfo structure.
*
*/
REAL SVK_hessian(f_info)
struct qinfo *f_info;
{
return SVK_all(f_info,METHOD_HESSIAN);
}
/***********************************************************************/
/************************************************************************
Named method: Neo_Hookean
Written by Dr. Rabah Bouzidi
************************************************************************/
#define NEO_LAMBDA_NAME "neo_lambda"
#define NEO_MU_NAME "neo_mu"
#define FORM_FACTORS_NAME "form_factors"
/***************************************************************
*
* function: Neo_Hookean_init()
*
* purpose: Make sure needed extra attributes are present.
*
*/
void Neo_Hookean_init(mode,mi)
int mode; /* energy or gradient */
struct method_instance *mi;
{
if ( web.modeltype != LINEAR )
kb_error(2819,"Neo_Hookean method only for LINEAR model.\n",RECOVERABLE);
if ( web.dimension != 2 )
kb_error(2829,"Neo_Hookean method only for SOAPFILM model.\n",
RECOVERABLE);
/* extra edge atribute */
lambda_attr = find_attribute(FACET,NEO_LAMBDA_NAME);
if ( lambda_attr < 0 ) /* not found */
kb_error(2837,"Facet extra attribute neo_lambda missing. Needed by Neo_Hookean.\n",RECOVERABLE);
mu_attr = find_attribute(FACET,NEO_MU_NAME);
if ( mu_attr < 0 ) /* not found */
kb_error(2838,"Facet extra attribute neo_mu missing. Needed by Neo_Hookean.\n",RECOVERABLE);
form_factors_attr = find_attribute(FACET,FORM_FACTORS_NAME);
if ( form_factors_attr < 0 ) /* not found */
kb_error(2839,"Facet extra attribute form_factors real[3] missing. Needed by Neo_Hookean.\n",RECOVERABLE);
if ( EXTRAS(FACET)[form_factors_attr].array_spec.datacount != 3 )
kb_error(2850,"Facet extra attribute form_factors must have size 3.\n",
RECOVERABLE);
}
/************************************************************************
*
* function: neo_Hookean_all()
*
* purpose: energy, gradient, and hessian for neo_Hookean method.
*/
REAL Neo_Hookean_all ARGS((struct qinfo *,int));
REAL Neo_Hookean_all(f_info,mode)
struct qinfo *f_info;
int mode; /* METHOD_VALUE, METHOD_GRADIENT, or METHOD_HESSIAN */
{
REAL *s; /* pointer to extra attributes */
REAL **side;
REAL q11,q12,q22; /* Q entries */
REAL det; /* det S */
REAL lambda; /* coefficient lambda */
REAL area; /* reference area of facet */
REAL mu; /* coefficient mu */
REAL f11,f12,f22;
REAL c11,c12,c21,c22, c33;
REAL energy;
REAL dc11dv[FACET_VERTS][MAXCOORD];
REAL dc12dv[FACET_VERTS][MAXCOORD];
REAL dc21dv[FACET_VERTS][MAXCOORD];
REAL dc22dv[FACET_VERTS][MAXCOORD];
REAL ddc11dv[FACET_VERTS][MAXCOORD][FACET_VERTS];
REAL ddc12dv[FACET_VERTS][MAXCOORD][FACET_VERTS];
REAL ddc21dv[FACET_VERTS][MAXCOORD][FACET_VERTS];
REAL ddc22dv[FACET_VERTS][MAXCOORD][FACET_VERTS];
/* potential derivatives declaration */
REAL dpsirdc11,dpsirdc12,dpsirdc21,dpsirdc22;
REAL ddpsirdc11dc11, ddpsirdc11dc12, ddpsirdc11dc21, ddpsirdc11dc22;
REAL ddpsirdc12dc11, ddpsirdc12dc12, ddpsirdc12dc21, ddpsirdc12dc22;
REAL ddpsirdc21dc11, ddpsirdc21dc12, ddpsirdc21dc21, ddpsirdc21dc22;
REAL ddpsirdc22dc11, ddpsirdc22dc12, ddpsirdc22dc21, ddpsirdc22dc22;
REAL s1, s2, s3, s4, s5, s6, s7;
REAL LW, tmp1, tmp2, logtmp2;
int i,j,ii,jj;
REAL detr;
lambda = *(REAL*)get_extra(f_info->id,lambda_attr);
mu = *(REAL*)get_extra(f_info->id,mu_attr);
s = (REAL*)get_extra(f_info->id,form_factors_attr);
det = s[0]*s[2] - s[1]*s[1];
if ( det <= 0.0 )
{
if ( mode == METHOD_VALUE ) return 0.0;
sprintf(errmsg," Neo_Hookean: Facet %d has unstrained area 0.\n",
ordinal(f_info->id)+1);
kb_error(2852,errmsg,RECOVERABLE);
}
area = sqrt(det)/2.0;
q11 = s[2]/det; q12 = -s[1]/det; q22 = s[0]/det;
side = f_info->sides[0];
f11 = SDIM_dot(side[0],side[0]);
f12 = SDIM_dot(side[0],side[1]);
f22 = SDIM_dot(side[1],side[1]);
c11 = f11*q11 + f12*q12 ;
c12 = f11*q12 + f12*q22;
c21 = f12*q11 + f22*q12;
c22 = f12*q12 + f22*q22;
detr = c11*c22-c12*c21;
/* plane stress condition */
LW = LambertW(2.0*mu/detr/lambda*exp(2.0*mu/lambda));
c33 = exp((-LW*lambda+2.0*mu)/lambda)/detr;
tmp1 = log(exp(-LW+2.0*mu/lambda));
tmp2 = exp(-(LW*lambda-2.0*mu)/lambda);
logtmp2 = log(tmp2);
energy =area*(mu*c11/2.0+mu*c22/2.0+mu/exp(LW)*pow(exp(mu/lambda),2.0)/(detr)/2.0-3.0/2.0*mu-mu*tmp1/2.0+lambda*pow(tmp1,2.0)/8.0);
if ( mode == METHOD_VALUE ) return energy;
/* gradient */
for ( i = 0 ; i < SDIM ; i++ )
{
dc11dv[1][i] = 2*side[0][i]*q11 + side[1][i]*q12;
dc11dv[2][i] = side[0][i]*q12;
dc12dv[1][i] = 2*side[0][i]*q12 + side[1][i]*q22;
dc12dv[2][i] = side[0][i]*q22;
dc21dv[1][i] = side[1][i]*q11;
dc21dv[2][i] = side[0][i]*q11 + 2*side[1][i]*q12;
dc22dv[1][i] = side[1][i]*q12;
dc22dv[2][i] = side[0][i]*q12 + 2*side[1][i]*q22;
dc11dv[0][i] = -(dc11dv[1][i] + dc11dv[2][i]);
dc12dv[0][i] = -(dc12dv[1][i] + dc12dv[2][i]);
dc21dv[0][i] = -(dc21dv[1][i] + dc21dv[2][i]);
dc22dv[0][i] = -(dc22dv[1][i] + dc22dv[2][i]);
}
s1 = (1/(pow(detr,2.0))*LW/(1.0+LW)*c22*exp(-LW+2.0*mu/lambda)/2.0-1/(pow(detr,2.0))*c22*exp(-LW+2.0*mu/lambda)/2.0-LW/(1.0+LW)/(detr)*c22/2.0+1.0/2.0)*mu;
s2 = lambda*tmp1*LW/(1.0+LW)/(detr)*c22/4.0;
dpsirdc11 = s1+s2;
s1 = c21/4.0;
s4 = 2.0*mu*tmp2+2.0*mu*LW*c11*c22;
s3 = s4-2.0*mu*LW*c12*c21-lambda*logtmp2*LW*c11*c22+lambda*logtmp2*LW*c12*c21;
s4 = 1/(pow(detr,2.0))/(1.0+LW);
s2 = s3*s4;
dpsirdc12 = s1*s2;
s1 = c12/4.0;
s4 = 2.0*mu*tmp2+2.0*mu*LW*c11*c22;
s3 = s4-2.0*mu*LW*c12*c21-lambda*logtmp2*LW*c11*c22+lambda*logtmp2*LW*c12*c21;
s4 = 1/(pow(detr,2.0))/(1.0+LW);
s2 = s3*s4;
dpsirdc21 = s1*s2;
s1 = (1/(pow(detr,2.0))*LW/(1.0+LW)*c11*exp(-LW+2.0*mu/lambda)/2.0-1/(pow(detr,2.0))*c11*exp(-LW+2.0*mu/lambda)/2.0-LW/(1.0+LW)/(detr)*c11/2.0+1.0/2.0)*mu;
s2 = lambda*tmp1*LW/(1.0+LW)/(detr)*c11/4.0;
dpsirdc22 = s1+s2;
for ( j = 0 ; j < FACET_VERTS ; j++ )
for ( i = 0 ; i < SDIM ; i++ )
{ f_info->grad[j][i] = area*(dpsirdc11*dc11dv[j][i]
+dpsirdc12*dc12dv[j][i]
+dpsirdc21*dc21dv[j][i]
+dpsirdc22*dc22dv[j][i]);
}
if ( mode == METHOD_GRADIENT ) return energy;
/* hessian */
for ( i = 0 ; i < SDIM ; i++ )
{
ddc11dv[1][i][1] = 2*q11;
ddc11dv[1][i][2] = q12;
ddc11dv[2][i][1] = q12;
ddc11dv[2][i][2] = 0.0;
ddc12dv[1][i][1] = 2*q12;
ddc12dv[1][i][2] = q22;
ddc12dv[2][i][1] = q22;
ddc12dv[2][i][2] = 0.0;
ddc21dv[1][i][1] = 0.0;
ddc21dv[1][i][2] = q11;
ddc21dv[2][i][1] = q11;
ddc21dv[2][i][2] = 2*q12;
ddc22dv[1][i][1] = 0.0;
ddc22dv[1][i][2] = q12;
ddc22dv[2][i][1] = q12;
ddc22dv[2][i][2] = 2*q22;
for ( j = 1 ; j < FACET_VERTS; j++ )
{
ddc11dv[0][i][j] = -(ddc11dv[1][i][j] + ddc11dv[2][i][j]);
ddc12dv[0][i][j] = -(ddc12dv[1][i][j] + ddc12dv[2][i][j]);
ddc21dv[0][i][j] = -(ddc21dv[1][i][j] + ddc21dv[2][i][j]);
ddc22dv[0][i][j] = -(ddc22dv[1][i][j] + ddc22dv[2][i][j]);
ddc11dv[j][i][0] = -(ddc11dv[j][i][1] + ddc11dv[j][i][2]);
ddc12dv[j][i][0] = -(ddc12dv[j][i][1] + ddc12dv[j][i][2]);
ddc21dv[j][i][0] = -(ddc21dv[j][i][1] + ddc21dv[j][i][2]);
ddc22dv[j][i][0] = -(ddc22dv[j][i][1] + ddc22dv[j][i][2]);
}
ddc11dv[0][i][0] = -(ddc11dv[1][i][0] + ddc11dv[2][i][0]);
ddc12dv[0][i][0] = -(ddc12dv[1][i][0] + ddc12dv[2][i][0]);
ddc21dv[0][i][0] = -(ddc21dv[1][i][0] + ddc21dv[2][i][0]);
ddc22dv[0][i][0] = -(ddc22dv[1][i][0] + ddc22dv[2][i][0]);
}
s1 = c22*c22/4.0;
s5 = 2.0*mu*pow(LW,2.0)*tmp2+4.0*mu*pow(LW,2.0)*c11*c22+4.0*mu*LW*c11*c22+4.0*mu*tmp2;
s4 = s5+4.0*mu*LW*tmp2-4.0*mu*pow(LW,2.0)*c12*c21-4.0*mu*LW*c12*c21+2.0*mu*pow(LW,3.0)*c11*c22-2.0*mu*pow(LW,3.0)*c12*c21;
s5 = s4-lambda*pow(LW,2.0)*c12*c21-2.0*lambda*logtmp2*LW*c11*c22+lambda*pow(LW,3.0)*c11*c22+lambda*pow(LW,2.0)*c11*c22;
s6 = s5+lambda*logtmp2*pow(LW,3.0)*c12*c21-lambda*logtmp2*pow(LW,3.0)*c11*c22;
s7 = s6-lambda*pow(LW,3.0)*c12*c21;
s3 = s7+2.0*lambda*logtmp2*pow(LW,2.0)*c12*c21+2.0*lambda*logtmp2*LW*c12*c21-2.0*lambda*logtmp2*pow(LW,2.0)*c11*c22;
s4 = 1/(pow(detr,3.0))/pow(1.0+LW,3.0);
s2 = s3*s4;
ddpsirdc11dc11 = s1*s2;
s1 = -c22*c21/4.0;
s5 = 2.0*mu*pow(LW,2.0)*tmp2+4.0*mu*pow(LW,2.0)*c11*c22+4.0*mu*LW*c11*c22+4.0*mu*tmp2;
s4 = s5+4.0*mu*LW*tmp2-4.0*mu*pow(LW,2.0)*c12*c21-4.0*mu*LW*c12*c21+2.0*mu*pow(LW,3.0)*c11*c22-2.0*mu*pow(LW,3.0)*c12*c21;
s5 = s4-lambda*pow(LW,2.0)*c12*c21-2.0*lambda*logtmp2*LW*c11*c22+lambda*pow(LW,3.0)*c11*c22+lambda*pow(LW,2.0)*c11*c22;
s6 = s5+lambda*logtmp2*pow(LW,3.0)*c12*c21-lambda*logtmp2*pow(LW,3.0)*c11*c22;
s7 = s6-lambda*pow(LW,3.0)*c12*c21;
s3 = s7+2.0*lambda*logtmp2*pow(LW,2.0)*c12*c21+2.0*lambda*logtmp2*LW*c12*c21-2.0*lambda*logtmp2*pow(LW,2.0)*c11*c22;
s4 = 1/(pow(detr,3.0))/pow(1.0+LW,3.0);
s2 = s3*s4;
ddpsirdc11dc12 = s1*s2;
s1 = -c22*c12/4.0;
s5 = 2.0*mu*pow(LW,2.0)*tmp2+4.0*mu*pow(LW,2.0)*c11*c22+4.0*mu*LW*c11*c22+4.0*mu*tmp2;
s4 = s5+4.0*mu*LW*tmp2-4.0*mu*pow(LW,2.0)*c12*c21-4.0*mu*LW*c12*c21+2.0*mu*pow(LW,3.0)*c11*c22-2.0*mu*pow(LW,3.0)*c12*c21;
s5 = s4-lambda*pow(LW,2.0)*c12*c21-2.0*lambda*logtmp2*LW*c11*c22+lambda*pow(LW,3.0)*c11*c22+lambda*pow(LW,2.0)*c11*c22;
s6 = s5+lambda*logtmp2*pow(LW,3.0)*c12*c21-lambda*logtmp2*pow(LW,3.0)*c11*c22;
s7 = s6-lambda*pow(LW,3.0)*c12*c21;
s3 = s7+2.0*lambda*logtmp2*pow(LW,2.0)*c12*c21+2.0*lambda*logtmp2*LW*c12*c21-2.0*lambda*logtmp2*pow(LW,2.0)*c11*c22;
s4 = 1/(pow(detr,3.0))/pow(1.0+LW,3.0);
s2 = s3*s4;
ddpsirdc11dc21 = s1*s2;
s3 = mu*tmp2*c12*c21/2.0+mu*LW*c11*c11*c22*c22/2.0+lambda*pow(LW,3.0)*c11*c11*c22*c22/4.0+lambda*pow(LW,2.0)*c11*c11*c22*c22/4.0-mu*pow(LW,3.0)*c12*c12*c21*c21/2.0;
s4 = s3-mu*pow(LW,2.0)*c12*c12*c21*c21-mu*LW*c12*c12*c21*c21/2.0;
s2 = s4+mu*c22*c11*tmp2/2.0+mu*LW*tmp2*c12*c21+mu*pow(LW,2.0)*tmp2*c12*c21/2.0;
s4 = s2-lambda*logtmp2*pow(LW,3.0)*c11*c22*c12*c21/4.0;
s3 = s4-lambda*logtmp2*pow(LW,2.0)*c11*c22*c12*c21/2.0-lambda*logtmp2*LW*c11*c11*c22*c22/4.0-lambda*pow(LW,3.0)*c11*c22*c12*c21/4.0;
s4 = s3-lambda*pow(LW,2.0)*c11*c22*c12*c21/4.0+mu*pow(LW,3.0)*c11*c22*c12*c21/2.0;
s5 = s4+mu*pow(LW,2.0)*c11*c22*c12*c21;
s1 = s5+lambda*logtmp2*pow(LW,3.0)*c12*c12*c21*c21/4.0+lambda*logtmp2*LW*c12*c12*c21*c21/4.0+lambda*logtmp2*pow(LW,2.0)*c12*c12*c21*c21/2.0;
s2 = 1/(pow(detr,3.0))/pow(1.0+LW,3.0);
ddpsirdc11dc22 = s1*s2;
s1 = c21*c22/4.0;
s6 = lambda*logtmp2*pow(LW,3.0)*c11*c22-lambda*logtmp2*pow(LW,3.0)*c12*c21;
s5 = s6+2.0*lambda*logtmp2*LW*c11*c22+2.0*lambda*logtmp2*pow(LW,2.0)*c11*c22;
s6 = s5-2.0*lambda*logtmp2*LW*c12*c21-2.0*lambda*logtmp2*pow(LW,2.0)*c12*c21;
s4 = s6-4.0*mu*tmp2-4.0*mu*LW*tmp2-2.0*mu*pow(LW,2.0)*tmp2;
s5 = s4+4.0*mu*pow(LW,2.0)*c12*c21+4.0*mu*LW*c12*c21-4.0*mu*pow(LW,2.0)*c11*c22-4.0*mu*LW*c11*c22;
s3 = s5-2.0*mu*pow(LW,3.0)*c11*c22+lambda*pow(LW,3.0)*c12*c21+lambda*pow(LW,2.0)*c12*c21-lambda*pow(LW,3.0)*c11*c22-lambda*pow(LW,2.0)*c11*c22+2.0*mu*pow(LW,3.0)*c12*c21;
s4 = 1/(pow(detr,3.0))/pow(1.0+LW,3.0);
s2 = s3*s4;
ddpsirdc12dc11 = s1*s2;
s1 = -c21*c21/4.0;
s6 = lambda*logtmp2*pow(LW,3.0)*c11*c22-lambda*logtmp2*pow(LW,3.0)*c12*c21;
s5 = s6+2.0*lambda*logtmp2*LW*c11*c22+2.0*lambda*logtmp2*pow(LW,2.0)*c11*c22;
s6 = s5-2.0*lambda*logtmp2*LW*c12*c21-2.0*lambda*logtmp2*pow(LW,2.0)*c12*c21;
s4 = s6-4.0*mu*tmp2-4.0*mu*LW*tmp2-2.0*mu*pow(LW,2.0)*tmp2;
s5 = s4+4.0*mu*pow(LW,2.0)*c12*c21+4.0*mu*LW*c12*c21-4.0*mu*pow(LW,2.0)*c11*c22-4.0*mu*LW*c11*c22;
s3 = s5-2.0*mu*pow(LW,3.0)*c11*c22+lambda*pow(LW,3.0)*c12*c21+lambda*pow(LW,2.0)*c12*c21-lambda*pow(LW,3.0)*c11*c22-lambda*pow(LW,2.0)*c11*c22+2.0*mu*pow(LW,3.0)*c12*c21;
s4 = 1/(pow(detr,3.0))/pow(1.0+LW,3.0);
s2 = s3*s4;
ddpsirdc12dc12 = s1*s2;
s3 = -mu*LW*c12*c12*c21*c21/2.0-lambda*pow(LW,3.0)*c12*c12*c21*c21/4.0-lambda*pow(LW,2.0)*c12*c12*c21*c21/4.0+mu*pow(LW,3.0)*c11*c11*c22*c22/2.0+mu*pow(LW,2.0)*c11*c11*c22*c22;
s4 = s3+mu*c21*c12*tmp2/2.0+mu*pow(LW,2.0)*tmp2*c11*c22/2.0;
s2 = s4+mu*LW*tmp2*c11*c22-mu*pow(LW,2.0)*c12*c21*c11*c22+mu*tmp2*c11*c22/2.0;
s3 = s2+lambda*logtmp2*LW*c12*c12*c21*c21/4.0+lambda*pow(LW,3.0)*c12*c21*c11*c22/4.0+lambda*pow(LW,2.0)*c12*c21*c11*c22/4.0+mu*LW*c11*c11*c22*c22/2.0;
s4 = s3-mu*pow(LW,3.0)*c12*c21*c11*c22/2.0+lambda*logtmp2*pow(LW,2.0)*c12*c21*c11*c22/2.0;
s5 = s4+lambda*logtmp2*pow(LW,3.0)*c12*c21*c11*c22/4.0;
s1 = s5-lambda*logtmp2*pow(LW,3.0)*c11*c11*c22*c22/4.0-lambda*logtmp2*LW*c11*c11*c22*c22/4.0-lambda*logtmp2*pow(LW,2.0)*c11*c11*c22*c22/2.0;
s2 = 1/(pow(detr,3.0))/pow(1.0+LW,3.0);
ddpsirdc12dc21 = s1*s2;
s1 = c21*c11/4.0;
s6 = lambda*logtmp2*pow(LW,3.0)*c11*c22-lambda*logtmp2*pow(LW,3.0)*c12*c21;
s5 = s6+2.0*lambda*logtmp2*LW*c11*c22+2.0*lambda*logtmp2*pow(LW,2.0)*c11*c22;
s6 = s5-2.0*lambda*logtmp2*LW*c12*c21-2.0*lambda*logtmp2*pow(LW,2.0)*c12*c21;
s4 = s6-4.0*mu*tmp2-4.0*mu*LW*tmp2-2.0*mu*pow(LW,2.0)*tmp2;
s5 = s4+4.0*mu*pow(LW,2.0)*c12*c21+4.0*mu*LW*c12*c21-4.0*mu*pow(LW,2.0)*c11*c22-4.0*mu*LW*c11*c22;
s3 = s5-2.0*mu*pow(LW,3.0)*c11*c22+lambda*pow(LW,3.0)*c12*c21+lambda*pow(LW,2.0)*c12*c21-lambda*pow(LW,3.0)*c11*c22-lambda*pow(LW,2.0)*c11*c22+2.0*mu*pow(LW,3.0)*c12*c21;
s4 = 1/(pow(detr,3.0))/pow(1.0+LW,3.0);
s2 = s3*s4;
ddpsirdc12dc22 = s1*s2;
s1 = c12*c22/4.0;
s5 = 4.0*mu*pow(LW,2.0)*c12*c21+4.0*mu*LW*c12*c21-4.0*mu*pow(LW,2.0)*c11*c22-4.0*mu*LW*c11*c22;
s4 = s5-2.0*mu*pow(LW,3.0)*c11*c22+2.0*mu*pow(LW,3.0)*c12*c21+lambda*pow(LW,2.0)*c12*c21-lambda*pow(LW,3.0)*c11*c22-lambda*pow(LW,2.0)*c11*c22;
s5 = s4+lambda*pow(LW,3.0)*c12*c21-4.0*mu*tmp2-4.0*mu*LW*tmp2-2.0*mu*pow(LW,2.0)*tmp2;
s6 = s5-2.0*lambda*logtmp2*pow(LW,2.0)*c12*c21-2.0*lambda*logtmp2*LW*c12*c21;
s7 = s6+2.0*lambda*logtmp2*pow(LW,2.0)*c11*c22;
s3 = s7+2.0*lambda*logtmp2*LW*c11*c22+lambda*logtmp2*pow(LW,3.0)*c11*c22-lambda*logtmp2*pow(LW,3.0)*c12*c21;
s4 = 1/(pow(detr,3.0))/pow(1.0+LW,3.0);
s2 = s3*s4;
ddpsirdc21dc11 = s1*s2;
s4 = -lambda*logtmp2*pow(LW,3.0)*c11*c11*c22*c22/4.0-lambda*logtmp2*LW*c11*c11*c22*c22/4.0;
s3 = s4-lambda*logtmp2*pow(LW,2.0)*c11*c11*c22*c22/2.0+lambda*logtmp2*pow(LW,3.0)*c21*c12*c11*c22/4.0-mu*LW*c21*c21*c12*c12/2.0;
s2 = s3+mu*tmp2*c11*c22/2.0+mu*LW*c11*c11*c22*c22/2.0-lambda*pow(LW,3.0)*c21*c21*c12*c12/4.0-lambda*pow(LW,2.0)*c21*c21*c12*c12/4.0+mu*pow(LW,3.0)*c11*c11*c22*c22/2.0;
s3 = s2+mu*pow(LW,2.0)*c11*c11*c22*c22+mu*c12*c21*tmp2/2.0+mu*pow(LW,2.0)*tmp2*c11*c22/2.0+mu*LW*tmp2*c11*c22;
s4 = s3-mu*pow(LW,2.0)*c21*c12*c11*c22-mu*pow(LW,3.0)*c21*c12*c11*c22/2.0;
s1 = s4+lambda*logtmp2*LW*c21*c21*c12*c12/4.0+lambda*logtmp2*pow(LW,2.0)*c21*c12*c11*c22/2.0+lambda*pow(LW,3.0)*c21*c12*c11*c22/4.0+lambda*pow(LW,2.0)*c21*c12*c11*c22/4.0;
s2 = 1/(pow(detr,3.0))/pow(1.0+LW,3.0);
ddpsirdc21dc12 = s1*s2;
s1 = -c12*c12/4.0;
s5 = 4.0*mu*pow(LW,2.0)*c12*c21+4.0*mu*LW*c12*c21-4.0*mu*pow(LW,2.0)*c11*c22-4.0*mu*LW*c11*c22;
s4 = s5-2.0*mu*pow(LW,3.0)*c11*c22+2.0*mu*pow(LW,3.0)*c12*c21+lambda*pow(LW,2.0)*c12*c21-lambda*pow(LW,3.0)*c11*c22-lambda*pow(LW,2.0)*c11*c22;
s5 = s4+lambda*pow(LW,3.0)*c12*c21-4.0*mu*tmp2-4.0*mu*LW*tmp2-2.0*mu*pow(LW,2.0)*tmp2;
s6 = s5-2.0*lambda*logtmp2*pow(LW,2.0)*c12*c21-2.0*lambda*logtmp2*LW*c12*c21;
s7 = s6+2.0*lambda*logtmp2*pow(LW,2.0)*c11*c22;
s3 = s7+2.0*lambda*logtmp2*LW*c11*c22+lambda*logtmp2*pow(LW,3.0)*c11*c22-lambda*logtmp2*pow(LW,3.0)*c12*c21;
s4 = 1/(pow(detr,3.0))/pow(1.0+LW,3.0);
s2 = s3*s4;
ddpsirdc21dc21 = s1*s2;
s1 = c12*c11/4.0;
s5 = 4.0*mu*pow(LW,2.0)*c12*c21+4.0*mu*LW*c12*c21-4.0*mu*pow(LW,2.0)*c11*c22-4.0*mu*LW*c11*c22;
s4 = s5-2.0*mu*pow(LW,3.0)*c11*c22+2.0*mu*pow(LW,3.0)*c12*c21+lambda*pow(LW,2.0)*c12*c21-lambda*pow(LW,3.0)*c11*c22-lambda*pow(LW,2.0)*c11*c22;
s5 = s4+lambda*pow(LW,3.0)*c12*c21-4.0*mu*tmp2-4.0*mu*LW*tmp2-2.0*mu*pow(LW,2.0)*tmp2;
s6 = s5-2.0*lambda*logtmp2*pow(LW,2.0)*c12*c21-2.0*lambda*logtmp2*LW*c12*c21;
s7 = s6+2.0*lambda*logtmp2*pow(LW,2.0)*c11*c22;
s3 = s7+2.0*lambda*logtmp2*LW*c11*c22+lambda*logtmp2*pow(LW,3.0)*c11*c22-lambda*logtmp2*pow(LW,3.0)*c12*c21;
s4 = 1/(pow(detr,3.0))/pow(1.0+LW,3.0);
s2 = s3*s4;
ddpsirdc21dc22 = s1*s2;
s3 = mu*LW*c22*c22*c11*c11/2.0-mu*pow(LW,3.0)*c12*c12*c21*c21/2.0-mu*pow(LW,2.0)*c12*c12*c21*c21-mu*LW*c12*c12*c21*c21/2.0+lambda*pow(LW,2.0)*c22*c22*c11*c11/4.0;
s4 = s3+lambda*pow(LW,3.0)*c22*c22*c11*c11/4.0+mu*LW*tmp2*c12*c21;
s2 = s4+mu*c11*c22*tmp2/2.0-lambda*logtmp2*pow(LW,3.0)*c22*c11*c12*c21/4.0-lambda*logtmp2*pow(LW,2.0)*c22*c11*c12*c21/2.0;
s3 = s2-lambda*pow(LW,3.0)*c22*c11*c12*c21/4.0-lambda*pow(LW,2.0)*c22*c11*c12*c21/4.0-lambda*logtmp2*LW*c22*c22*c11*c11/4.0+mu*pow(LW,3.0)*c22*c11*c12*c21/2.0;
s4 = s3+mu*pow(LW,2.0)*c22*c11*c12*c21+mu*tmp2*c12*c21/2.0;
s5 = s4+mu*pow(LW,2.0)*tmp2*c12*c21/2.0;
s1 = s5+lambda*logtmp2*pow(LW,2.0)*c12*c12*c21*c21/2.0+lambda*logtmp2*pow(LW,3.0)*c12*c12*c21*c21/4.0+lambda*logtmp2*LW*c12*c12*c21*c21/4.0;
s2 = 1/(pow(detr,3.0))/pow(1.0+LW,3.0);
ddpsirdc22dc11 = s1*s2;
s1 = c11*c21/4.0;
s6 = -4.0*mu*LW*tmp2-2.0*lambda*logtmp2*LW*c12*c21;
s5 = s6-2.0*lambda*logtmp2*pow(LW,2.0)*c12*c21+2.0*lambda*logtmp2*LW*c11*c22;
s6 = s5+2.0*lambda*logtmp2*pow(LW,2.0)*c11*c22-2.0*mu*pow(LW,2.0)*tmp2;
s4 = s6-lambda*logtmp2*pow(LW,3.0)*c12*c21+lambda*logtmp2*pow(LW,3.0)*c11*c22-2.0*mu*pow(LW,3.0)*c11*c22;
s5 = s4+4.0*mu*pow(LW,2.0)*c12*c21+4.0*mu*LW*c12*c21-4.0*mu*pow(LW,2.0)*c11*c22-4.0*mu*LW*c11*c22;
s3 = s5+lambda*pow(LW,3.0)*c12*c21+lambda*pow(LW,2.0)*c12*c21-lambda*pow(LW,3.0)*c11*c22-lambda*pow(LW,2.0)*c11*c22+2.0*mu*pow(LW,3.0)*c12*c21-4.0*mu*tmp2;
s4 = 1/(pow(detr,3.0))/pow(1.0+LW,3.0);
ddpsirdc22dc12 = s1*s2;
s1 = c11*c12/4.0;
s6 = -4.0*mu*LW*tmp2-2.0*lambda*logtmp2*LW*c12*c21;
s5 = s6-2.0*lambda*logtmp2*pow(LW,2.0)*c12*c21+2.0*lambda*logtmp2*LW*c11*c22;
s6 = s5+2.0*lambda*logtmp2*pow(LW,2.0)*c11*c22-2.0*mu*pow(LW,2.0)*tmp2;
s4 = s6-lambda*logtmp2*pow(LW,3.0)*c12*c21+lambda*logtmp2*pow(LW,3.0)*c11*c22-2.0*mu*pow(LW,3.0)*c11*c22;
s5 = s4+4.0*mu*pow(LW,2.0)*c12*c21+4.0*mu*LW*c12*c21-4.0*mu*pow(LW,2.0)*c11*c22-4.0*mu*LW*c11*c22;
s3 = s5+lambda*pow(LW,3.0)*c12*c21+lambda*pow(LW,2.0)*c12*c21-lambda*pow(LW,3.0)*c11*c22-lambda*pow(LW,2.0)*c11*c22+2.0*mu*pow(LW,3.0)*c12*c21-4.0*mu*tmp2;
s4 = 1/(pow(detr,3.0))/pow(1.0+LW,3.0);
s2 = s3*s4;
ddpsirdc22dc21 = s1*s2;
s1 = -c11*c11/4.0;
s6 = -4.0*mu*LW*tmp2-2.0*lambda*logtmp2*LW*c12*c21;
s5 = s6-2.0*lambda*logtmp2*pow(LW,2.0)*c12*c21+2.0*lambda*logtmp2*LW*c11*c22;
s6 = s5+2.0*lambda*logtmp2*pow(LW,2.0)*c11*c22-2.0*mu*pow(LW,2.0)*tmp2;
s4 = s6-lambda*logtmp2*pow(LW,3.0)*c12*c21+lambda*logtmp2*pow(LW,3.0)*c11*c22-2.0*mu*pow(LW,3.0)*c11*c22;
s5 = s4+4.0*mu*pow(LW,2.0)*c12*c21+4.0*mu*LW*c12*c21-4.0*mu*pow(LW,2.0)*c11*c22-4.0*mu*LW*c11*c22;
s3 = s5+lambda*pow(LW,3.0)*c12*c21+lambda*pow(LW,2.0)*c12*c21-lambda*pow(LW,3.0)*c11*c22-lambda*pow(LW,2.0)*c11*c22+2.0*mu*pow(LW,3.0)*c12*c21-4.0*mu*tmp2;
s4 = 1/(pow(detr,3.0))/pow(1.0+LW,3.0);
s2 = s3*s4;
ddpsirdc22dc22 = s1*s2;
for ( j = 0 ; j < FACET_VERTS ; j++ )
for ( i = 0 ; i < SDIM ; i++ )
for ( jj = 0 ; jj < FACET_VERTS ; jj++ )
{
f_info->hess[j][jj][i][i] +=
area*(dpsirdc11*ddc11dv[j][i][jj]
+dpsirdc12*ddc21dv[j][i][jj]
+dpsirdc21*ddc12dv[j][i][jj]
+dpsirdc22*ddc22dv[j][i][jj]);
for ( ii = 0 ; ii < SDIM ; ii++ )
f_info->hess[j][jj][i][ii] +=
area*((ddpsirdc11dc11+ddpsirdc12dc11+ddpsirdc21dc11+ddpsirdc22dc11)*dc11dv[j][i]
+(ddpsirdc11dc12+ddpsirdc12dc12+ddpsirdc21dc12+ddpsirdc22dc12)*dc12dv[j][i]
+(ddpsirdc11dc21+ddpsirdc12dc21+ddpsirdc21dc21+ddpsirdc22dc21)*dc21dv[j][i]
+(ddpsirdc11dc22+ddpsirdc12dc22+ddpsirdc21dc22+ddpsirdc22dc22)*dc22dv[j][i]);
}
return energy;
}
/* Lambert W function.
Was ~/C/LambertW.c written K M Briggs Keith dot Briggs at bt dot com 97 May 21.
Revised KMB 97 Nov 20; 98 Feb 11, Nov 24, Dec 28; 99 Jan 13; 00 Feb 23; 01 Apr 09
Computes Lambert W function, principal branch.
See LambertW1.c for -1 branch.
Returned value W(z) satisfies W(z)*exp(W(z))=z
test data...
W(1)= 0.5671432904097838730
W(2)= 0.8526055020137254914
W(20)=2.2050032780240599705
To solve (a+b*R)*exp(-c*R)-d=0 for R, use
R=-(b*W(-exp(-a*c/b)/b*d*c)+a*c)/b/c
Test:
gcc -DTESTW LambertW.c -o LambertW -lm && LambertW
Library:
gcc -O3 -c LambertW.c
*/
REAL LambertW(z)
REAL z;
{
int i;
const REAL eps=4.0e-16, em1=0.3678794411714423215955237701614608;
REAL p,e,t,w;
if (z<-em1 || !is_finite(z)) {
fprintf(stderr,"LambertW: bad argument %g, exiting.\n",z); exit(1);
}
if (0.0==z) return 0.0;
if (z<-em1+1e-4) { /* series near -em1 in sqrt(q) */
double q=z+em1,r=sqrt(q),q2=q*q,q3=q2*q;
w = -1.0
+2.331643981597124203363536062168*r
-1.812187885639363490240191647568*q
+1.936631114492359755363277457668*r*q
-2.353551201881614516821543561516*q2
+3.066858901050631912893148922704*r*q2
-4.175335600258177138854984177460*q3
+5.858023729874774148815053846119*r*q3
-8.401032217523977370984161688514*q3*q; /* error approx 1e-16 */
fprintf(stderr,"LambertW expression 1: W(%15.12g) = %15.12g \n",z,w);
return w;
}
/* initial approx for iteration... */
if (z<1.0) { /* series near 0 */
p=sqrt(2.0*(2.7182818284590452353602874713526625*z+1.0));
w=-1.0+p*(1.0+p*(-0.333333333333333333333+p*0.152777777777777777777777));
} else
w=log(z); /* asymptotic */
if (z>3.0) w-=log(w); /* useful? */
for (i=0; i<10; i++) { /* Halley iteration */
e=exp(w);
t=w*e-z;
p=w+1.0;
t/=e*p-0.5*(p+1.0)*t/p;
w-=t;
if (fabs(t)array_spec.dim != 2 || ex->array_spec.sizes[0] != 2 || ex->array_spec.sizes[1] != 2 )
kb_error(3204,
"Facet extra attribute elastic_basis must have dimension [2][2].\n",
RECOVERABLE);
ex = &EXTRAS(FACET)[coeff_attr];
if ( ex->array_spec.dim != 1 || ex->array_spec.sizes[0] != 6 )
kb_error(3205,
"Facet extra attribute elastic_coeff must have 1 dimension and size 6.\n",
RECOVERABLE);
}
/************************************************************************
*
* function: general_linear_elastic_all()
*
* purpose: energy, gradient, and hessian for linear_elastic method.
*/
REAL general_linear_elastic_all ARGS((struct qinfo *,int));
REAL general_linear_elastic_all(f_info,mode)
struct qinfo *f_info;
int mode; /* METHOD_VALUE, METHOD_GRADIENT, or METHOD_HESSIAN */
{
REAL s[2][2],*sptr; /* pointer to extra attributes */
REAL **side;
REAL q11,q12,q21,q22; /* Q entries */
REAL det; /* det S */
REAL area; /* reference area of facet */
REAL * coeff; /* elastic coeff extra attribute */
REAL elastic_coeff[2][2][2][2];
REAL f11,f12,f21,f22;
REAL c11,c12,c21,c22;
REAL energy;
REAL dc11dv[FACET_VERTS][MAXCOORD];
REAL dc12dv[FACET_VERTS][MAXCOORD];
REAL dc21dv[FACET_VERTS][MAXCOORD];
REAL dc22dv[FACET_VERTS][MAXCOORD];
REAL ddc11dv[FACET_VERTS][MAXCOORD][FACET_VERTS];
REAL ddc12dv[FACET_VERTS][MAXCOORD][FACET_VERTS];
REAL ddc21dv[FACET_VERTS][MAXCOORD][FACET_VERTS];
REAL ddc22dv[FACET_VERTS][MAXCOORD][FACET_VERTS];
int i,j,ii,jj;
coeff = (REAL*)get_extra(f_info->id,coeff_attr);
elastic_coeff[0][0][0][0] = coeff[0];
elastic_coeff[1][1][1][1] = coeff[1];
elastic_coeff[0][0][1][1] = coeff[2];
elastic_coeff[1][1][0][0] = coeff[2];
elastic_coeff[0][0][0][1] = coeff[3]/2;
elastic_coeff[0][0][1][0] = coeff[3]/2;
elastic_coeff[0][1][0][0] = coeff[3]/2;
elastic_coeff[1][0][0][0] = coeff[3]/2;
elastic_coeff[1][1][1][0] = coeff[4]/2;
elastic_coeff[0][1][1][1] = coeff[4]/2;
elastic_coeff[1][0][1][1] = coeff[4]/2;
elastic_coeff[1][1][0][1] = coeff[4]/2;
elastic_coeff[1][0][1][0] = coeff[5]/4;
elastic_coeff[1][0][0][1] = coeff[5]/4;
elastic_coeff[0][1][0][1] = coeff[5]/4;
elastic_coeff[0][1][1][0] = coeff[5]/4;
/* get unstrained sides in columns of S and get inverse */
sptr = (REAL*)get_extra(f_info->id,elastic_base_attr);
s[0][0] = sptr[0]; s[1][0] = sptr[1]; s[0][1] = sptr[2]; s[1][1] = sptr[3];
det = s[0][0]*s[1][1] - s[0][1]*s[1][0];
if ( det == 0.0 )
{ if ( mode == METHOD_VALUE ) return 0.0;
sprintf(errmsg,
"general_linear_elastic: Facet %s has unstrained area 0.\n",
ELNAME(f_info->id));
kb_error(3206,errmsg,RECOVERABLE);
}
area = fabs(det)/2;
q11 = s[1][1]/det; q12 = -s[0][1]/det; q21 = -s[1][0]/det; q22 = s[0][0]/det;
/* Gram matrix of strained sides */
side = f_info->sides[0];
f11 = SDIM_dot(side[0],side[0]);
f21 = f12 = SDIM_dot(side[0],side[1]);
f22 = SDIM_dot(side[1],side[1]);
/* Strain matrix */
c11 = (q11*f11*q11 + q11*f12*q21 + q21*f21*q11 + q21*f22*q21 - 1)/2;
c12 = (q11*f11*q12 + q11*f12*q22 + q21*f21*q12 + q21*f22*q22)/2;
c21 = c12;
c22 = (q12*f11*q12 + q12*f12*q22 + q22*f21*q12 + q22*f22*q22 - 1)/2;
energy = c11*c11*elastic_coeff[0][0][0][0]
+ c11*c12*elastic_coeff[0][0][0][1]
+ c11*c22*elastic_coeff[0][0][1][1]
+ c11*c21*elastic_coeff[0][0][1][0]
+ c12*c11*elastic_coeff[0][1][0][0]
+ c12*c12*elastic_coeff[0][1][0][1]
+ c12*c22*elastic_coeff[0][1][1][1]
+ c12*c21*elastic_coeff[0][1][1][0]
+ c21*c11*elastic_coeff[1][0][0][0]
+ c21*c12*elastic_coeff[1][0][0][1]
+ c21*c22*elastic_coeff[1][0][1][1]
+ c21*c21*elastic_coeff[1][0][1][0]
+ c22*c11*elastic_coeff[1][1][0][0]
+ c22*c12*elastic_coeff[1][1][0][1]
+ c22*c22*elastic_coeff[1][1][1][1]
+ c22*c21*elastic_coeff[1][1][1][0] ;
energy *= area/2;
if ( mode == METHOD_VALUE ) return energy;
/* gradient */
for ( i = 0 ; i < SDIM ; i++ )
{
dc11dv[1][i] = (q11*2*side[0][i]*q11 + q11*side[1][i]*q21 + q21*side[1][i]*q11 )/2;
dc11dv[2][i] = (q11*side[0][i]*q21 + q21*side[0][i]*q11 + q21*2*side[1][i]*q21 )/2;
dc12dv[1][i] = (q11*2*side[0][i]*q12 + q11*side[1][i]*q22 + q21*side[1][i]*q12 )/2;
dc12dv[2][i] = (q11*side[0][i]*q22 + q21*side[0][i]*q12 + q21*2*side[1][i]*q22 )/2;
dc21dv[1][i] = dc12dv[1][i];
dc21dv[2][i] = dc12dv[2][i];
dc22dv[1][i] = (q12*2*side[0][i]*q12 + q12*side[1][i]*q22 + q22*side[1][i]*q12 )/2;
dc22dv[2][i] = (q12*side[0][i]*q22 + q22*side[0][i]*q12 + q22*2*side[1][i]*q22 )/2;
dc11dv[0][i] = -(dc11dv[1][i] + dc11dv[2][i]);
dc12dv[0][i] = -(dc12dv[1][i] + dc12dv[2][i]);
dc21dv[0][i] = -(dc21dv[1][i] + dc21dv[2][i]);
dc22dv[0][i] = -(dc22dv[1][i] + dc22dv[2][i]);
}
for ( j = 0 ; j < FACET_VERTS ; j++ )
for ( i = 0 ; i < SDIM ; i++ )
{ f_info->grad[j][i] = area*(
c11*dc11dv[j][i]*elastic_coeff[0][0][0][0]
+ c11*dc12dv[j][i]*elastic_coeff[0][0][0][1]
+ c11*dc22dv[j][i]*elastic_coeff[0][0][1][1]
+ c11*dc21dv[j][i]*elastic_coeff[0][0][1][0]
+ c12*dc11dv[j][i]*elastic_coeff[0][1][0][0]
+ c12*dc12dv[j][i]*elastic_coeff[0][1][0][1]
+ c12*dc22dv[j][i]*elastic_coeff[0][1][1][1]
+ c12*dc21dv[j][i]*elastic_coeff[0][1][1][0]
+ c21*dc11dv[j][i]*elastic_coeff[1][0][0][0]
+ c21*dc12dv[j][i]*elastic_coeff[1][0][0][1]
+ c21*dc22dv[j][i]*elastic_coeff[1][0][1][1]
+ c21*dc21dv[j][i]*elastic_coeff[1][0][1][0]
+ c22*dc11dv[j][i]*elastic_coeff[1][1][0][0]
+ c22*dc12dv[j][i]*elastic_coeff[1][1][0][1]
+ c22*dc22dv[j][i]*elastic_coeff[1][1][1][1]
+ c22*dc21dv[j][i]*elastic_coeff[1][1][1][0]);
/* don't need to divide by 2 here, since only doing
derivative of second term and using symmetry */
}
if ( mode == METHOD_GRADIENT ) return energy;
/* hessian */
for ( i = 0 ; i < SDIM ; i++ )
{
ddc11dv[1][i][1] = (q11*2*q11)/2;
ddc11dv[1][i][2] = ( q11*q21 + q21*q11 )/2;
ddc11dv[2][i][1] = (q11*q21 + q21*q11 )/2;
ddc11dv[2][i][2] = (q21*2*q21)/2;
ddc12dv[1][i][1] = (q11*2*q12 )/2;
ddc12dv[1][i][2] = ( q11*q22 + q21*q12 )/2;
ddc12dv[2][i][1] = (q11*q22 + q21*q12)/2;
ddc12dv[2][i][2] = (q21*2*q22 )/2;
ddc21dv[1][i][1] = ddc12dv[1][i][1];
ddc21dv[1][i][2] = ddc12dv[1][i][2];
ddc21dv[2][i][1] = ddc12dv[2][i][1];
ddc21dv[2][i][2] = ddc12dv[2][i][2];
ddc22dv[1][i][1] = (q12*2*q12)/2;
ddc22dv[1][i][2] = (q12*q22 + q22*q12)/2;
ddc22dv[2][i][1] = (q12*q22 + q22*q12)/2;
ddc22dv[2][i][2] = (q22*2*q22)/2;
for ( j = 1 ; j < FACET_VERTS; j++ )
{
ddc11dv[0][i][j] = -(ddc11dv[1][i][j] + ddc11dv[2][i][j]);
ddc12dv[0][i][j] = -(ddc12dv[1][i][j] + ddc12dv[2][i][j]);
ddc21dv[0][i][j] = -(ddc21dv[1][i][j] + ddc21dv[2][i][j]);
ddc22dv[0][i][j] = -(ddc22dv[1][i][j] + ddc22dv[2][i][j]);
ddc11dv[j][i][0] = -(ddc11dv[j][i][1] + ddc11dv[j][i][2]);
ddc12dv[j][i][0] = -(ddc12dv[j][i][1] + ddc12dv[j][i][2]);
ddc21dv[j][i][0] = -(ddc21dv[j][i][1] + ddc21dv[j][i][2]);
ddc22dv[j][i][0] = -(ddc22dv[j][i][1] + ddc22dv[j][i][2]);
}
ddc11dv[0][i][0] = -(ddc11dv[1][i][0] + ddc11dv[2][i][0]);
ddc12dv[0][i][0] = -(ddc12dv[1][i][0] + ddc12dv[2][i][0]);
ddc21dv[0][i][0] = -(ddc21dv[1][i][0] + ddc21dv[2][i][0]);
ddc22dv[0][i][0] = -(ddc22dv[1][i][0] + ddc22dv[2][i][0]);
}
for ( j = 0 ; j < FACET_VERTS ; j++ )
for ( i = 0 ; i < SDIM ; i++ )
for ( jj = 0 ; jj < FACET_VERTS ; jj++ )
{
f_info->hess[j][jj][i][i] += area*(
c11*ddc11dv[j][i][jj]*elastic_coeff[0][0][0][0]
+ c11*ddc12dv[j][i][jj]*elastic_coeff[0][0][0][1]
+ c11*ddc22dv[j][i][jj]*elastic_coeff[0][0][1][1]
+ c11*ddc21dv[j][i][jj]*elastic_coeff[0][0][1][0]
+ c12*ddc11dv[j][i][jj]*elastic_coeff[0][1][0][0]
+ c12*ddc12dv[j][i][jj]*elastic_coeff[0][1][0][1]
+ c12*ddc22dv[j][i][jj]*elastic_coeff[0][1][1][1]
+ c12*ddc21dv[j][i][jj]*elastic_coeff[0][1][1][0]
+ c21*ddc11dv[j][i][jj]*elastic_coeff[1][0][0][0]
+ c21*ddc12dv[j][i][jj]*elastic_coeff[1][0][0][1]
+ c21*ddc22dv[j][i][jj]*elastic_coeff[1][0][1][1]
+ c21*ddc21dv[j][i][jj]*elastic_coeff[1][0][1][0]
+ c22*ddc11dv[j][i][jj]*elastic_coeff[1][1][0][0]
+ c22*ddc12dv[j][i][jj]*elastic_coeff[1][1][0][1]
+ c22*ddc22dv[j][i][jj]*elastic_coeff[1][1][1][1]
+ c22*ddc21dv[j][i][jj]*elastic_coeff[1][1][1][0]);
for ( ii = 0 ; ii < SDIM ; ii++ )
f_info->hess[j][jj][i][ii] += area*(
dc11dv[jj][ii]*dc11dv[j][i]*elastic_coeff[0][0][0][0]
+ dc11dv[jj][ii]*dc12dv[j][i]*elastic_coeff[0][0][0][1]
+ dc11dv[jj][ii]*dc22dv[j][i]*elastic_coeff[0][0][1][1]
+ dc11dv[jj][ii]*dc21dv[j][i]*elastic_coeff[0][0][1][0]
+ dc12dv[jj][ii]*dc11dv[j][i]*elastic_coeff[0][1][0][0]
+ dc12dv[jj][ii]*dc12dv[j][i]*elastic_coeff[0][1][0][1]
+ dc12dv[jj][ii]*dc22dv[j][i]*elastic_coeff[0][1][1][1]
+ dc12dv[jj][ii]*dc21dv[j][i]*elastic_coeff[0][1][1][0]
+ dc21dv[jj][ii]*dc11dv[j][i]*elastic_coeff[1][0][0][0]
+ dc21dv[jj][ii]*dc12dv[j][i]*elastic_coeff[1][0][0][1]
+ dc21dv[jj][ii]*dc22dv[j][i]*elastic_coeff[1][0][1][1]
+ dc21dv[jj][ii]*dc21dv[j][i]*elastic_coeff[1][0][1][0]
+ dc22dv[jj][ii]*dc11dv[j][i]*elastic_coeff[1][1][0][0]
+ dc22dv[jj][ii]*dc12dv[j][i]*elastic_coeff[1][1][0][1]
+ dc22dv[jj][ii]*dc22dv[j][i]*elastic_coeff[1][1][1][1]
+ dc22dv[jj][ii]*dc21dv[j][i]*elastic_coeff[1][1][1][0]);
}
return energy;
} /* end general_linear_elastic_all() */
/**************************************************************
*
* function: general_linear_elastic_energy()
*
* purpose: calculates energy of one facet due to potential
*
* input: info about vertex is in qinfo structure.
*
*/
REAL general_linear_elastic_energy(f_info)
struct qinfo *f_info;
{
return general_linear_elastic_all(f_info,METHOD_VALUE);
}
/**************************************************************
*
* function: general_linear_elastic_gradient()
*
* purpose: calculates gradient of one facet due to potential
*
* input: info about vertex is in qinfo structure.
*
*/
REAL general_linear_elastic_gradient(f_info)
struct qinfo *f_info;
{
return general_linear_elastic_all(f_info,METHOD_GRADIENT);
}
/**************************************************************
*
* function: general_linear_elastic_hessian()
*
* purpose: calculates hessian of one facet due to potential
*
* input: info about vertex is in qinfo structure.
*
*/
REAL general_linear_elastic_hessian(f_info)
struct qinfo *f_info;
{
return general_linear_elastic_all(f_info,METHOD_HESSIAN);
}
/***********************************************************************/
/************************************************************************
Named method: dirichlet_elastic
Dirichlet elastic strain energy on facets.
For conformal mappings.
Let S be Gram matrix of unstrained facet (dots of sides).
Let Q be the inverse of S.
Let F be Gram matrix of strained facet.
Let C = FQ, the linear deformation matrix
Then energy density is
Tr(CC^T)
Each facet extra attribute array form_factors[3] = {s11,s12,s22}
where sij = dot(si,sj) and s1 = (v1-v0), s2 = (v2-v0).
************************************************************************/
#define FORM_FACTORS_NAME "form_factors"
extern int form_factors_attr; /* number of form_factors extra attribute */
/***************************************************************
*
* function: dirichlet_elastic_init()
*
* purpose: Make sure needed extra attributes are present.
*
*
*/
void dirichlet_elastic_init(mode,mi)
int mode; /* energy or gradient or hessian */
struct method_instance *mi;
{
if ( web.modeltype != LINEAR )
kb_error(4529,"dirichlet_elastic method only for LINEAR model.\n",RECOVERABLE);
if ( web.dimension != 2 )
kb_error(4150,"dirichlet_elastic method only for SOAPFILM model.\n",
RECOVERABLE);
form_factors_attr = find_attribute(FACET,FORM_FACTORS_NAME);
if ( form_factors_attr < 0 ) /* not found */
kb_error(4152,"Facet extra attribute form_factors real[3] missing. Needed by dirichlet_elastic.\n",RECOVERABLE);
if ( EXTRAS(FACET)[form_factors_attr].array_spec.datacount < 3 )
kb_error(4153,"Facet extra attribute form_factors must have size 3.\n",
RECOVERABLE);
}
/************************************************************************
*
* function: dirichlet_elastic_all()
*
* purpose: energy, gradient, and hessian for dirichlet_elastic method.
*/
REAL dirichlet_elastic_all ARGS((struct qinfo *,int));
REAL dirichlet_elastic_all(f_info,mode)
struct qinfo *f_info;
int mode; /* METHOD_VALUE, METHOD_GRADIENT, or METHOD_HESSIAN */
{
REAL *s; /* pointer to extra attributes */
REAL **side;
REAL q11,q12,q22; /* Q entries */
REAL det; /* det S */
REAL area; /* reference area of facet */
REAL f11,f12,f22;
REAL c11,c22;
REAL energy;
REAL dc11dv[FACET_VERTS][MAXCOORD];
REAL dc22dv[FACET_VERTS][MAXCOORD];
REAL ddc11dv[FACET_VERTS][MAXCOORD][FACET_VERTS];
REAL ddc22dv[FACET_VERTS][MAXCOORD][FACET_VERTS];
int i,j,jj;
s = (REAL*)get_extra(f_info->id,form_factors_attr);
det = s[0]*s[2] - s[1]*s[1];
if ( det <= 0.0 )
{ if ( mode == METHOD_VALUE ) return 0.0;
sprintf(errmsg,"dirichlet_elastic: Facet %s has unstrained area <= 0.\n",
ELNAME(f_info->id));
kb_error(4154,errmsg,RECOVERABLE);
}
area = sqrt(det)/2;
q11 = s[2]/det; q12 = -s[1]/det; q22 = s[0]/det;
side = f_info->sides[0];
f11 = SDIM_dot(side[0],side[0]);
f12 = SDIM_dot(side[0],side[1]);
f22 = SDIM_dot(side[1],side[1]);
c11 = f11*q11 + f12*q12;
c22 = f12*q12 + f22*q22;
energy = (c11 + c22)*area;
if ( mode == METHOD_VALUE ) return energy;
/* gradient */
for ( i = 0 ; i < SDIM ; i++ )
{
dc11dv[1][i] = 2*side[0][i]*q11 + side[1][i]*q12;
dc11dv[2][i] = side[0][i]*q12;
dc22dv[1][i] = side[1][i]*q12;
dc22dv[2][i] = side[0][i]*q12 + 2*side[1][i]*q22;
dc11dv[0][i] = -(dc11dv[1][i] + dc11dv[2][i]);
dc22dv[0][i] = -(dc22dv[1][i] + dc22dv[2][i]);
}
for ( j = 0 ; j < FACET_VERTS ; j++ )
for ( i = 0 ; i < SDIM ; i++ )
{ f_info->grad[j][i] = (dc11dv[j][i] + dc22dv[j][i]) * area;
}
if ( mode == METHOD_GRADIENT ) return energy;
/* hessian */
for ( i = 0 ; i < SDIM ; i++ )
{
ddc11dv[1][i][1] = 2*q11;
ddc11dv[1][i][2] = q12;
ddc11dv[2][i][1] = q12;
ddc11dv[2][i][2] = 0.0;
ddc22dv[1][i][1] = 0.0;
ddc22dv[1][i][2] = q12;
ddc22dv[2][i][1] = q12;
ddc22dv[2][i][2] = 2*q22;
for ( j = 1 ; j < FACET_VERTS; j++ )
{
ddc11dv[0][i][j] = -(ddc11dv[1][i][j] + ddc11dv[2][i][j]);
ddc22dv[0][i][j] = -(ddc22dv[1][i][j] + ddc22dv[2][i][j]);
ddc11dv[j][i][0] = -(ddc11dv[j][i][1] + ddc11dv[j][i][2]);
ddc22dv[j][i][0] = -(ddc22dv[j][i][1] + ddc22dv[j][i][2]);
}
ddc11dv[0][i][0] = -(ddc11dv[1][i][0] + ddc11dv[2][i][0]);
ddc22dv[0][i][0] = -(ddc22dv[1][i][0] + ddc22dv[2][i][0]);
}
for ( j = 0 ; j < FACET_VERTS ; j++ )
for ( i = 0 ; i < SDIM ; i++ )
for ( jj = 0 ; jj < FACET_VERTS ; jj++ )
{
f_info->hess[j][jj][i][i] +=
(ddc11dv[j][i][jj] + ddc22dv[j][i][jj]) * area;
}
return energy;
}
/**************************************************************
*
* function: dirichlet_elastic_energy()
*
* purpose: calculates energy of one facet due to potential
*
* input: info about vertex is in qinfo structure.
*
*/
REAL dirichlet_elastic_energy(f_info)
struct qinfo *f_info;
{
return dirichlet_elastic_all(f_info,METHOD_VALUE);
}
/**************************************************************
*
* function: dirichlet_elastic_gradient()
*
* purpose: calculates gradient of one facet due to potential
*
* input: info about vertex is in qinfo structure.
*
*/
REAL dirichlet_elastic_gradient(f_info)
struct qinfo *f_info;
{
return dirichlet_elastic_all(f_info,METHOD_GRADIENT);
}
/**************************************************************
*
* function: dirichlet_elastic_hessian()
*
* purpose: calculates hessian of one facet due to potential
*
* input: info about vertex is in qinfo structure.
*
*/
REAL dirichlet_elastic_hessian(f_info)
struct qinfo *f_info;
{
return dirichlet_elastic_all(f_info,METHOD_HESSIAN);
}
evolver-2.30c.dfsg/src/Makefile 0000644 0001753 0001753 00000023346 11410765113 016665 0 ustar hazelsct hazelsct # Makefile for Surface Evolver
SHELL= /bin/sh
# INSTRUCTIONS: Customize this makefile for your system by choosing
# your compiler (cc or gcc or whatever), and then uncomment the
# appropriate CFLAGS, GRAPH, and GRAPHLIB definitions for your system.
# If lines need to be modified for your system, please let me know
# at brakke@susqu.edu.
# The following systems have their own sections:
# Generic Unix
# Linux OpenGL
# Linux Xwindows
# cygwin
# Mac OSX
# Sun Xwindows
# 32-bint Solaris OpenGL
# 64-bint Solaris OpenGL
# NOTE: -DOOGL should be specified in CFLAGS if you want Evolver to
# be able to use geomview. And -DOOGL is harmless in any case.
# NOTE: You can use the readline input editing system (if your system has it)
# by adding -DUSE_READLINE to CFLAGS and -lreadline -lcurses to GRAPHLIB.
# But beware; readline may be incompatible with using geomview.
# Also, the readline code was contributed by a user for version 2.30,
# and may be incompatible with readline libraries on some systems (Mac,
# for instance).
#-----------------------------------------------------------------------------
# Pick your compiler, and add any options you want, such as optimization
CC= cc
#CC= gcc
#---------------------Start of system choices---------------------------------
# Remove #'s from following 3 lines for generic Unix without builtin graphics.
# Add -DOOGL to CFLAGS if you are using geomview.
#CFLAGS= -DGENERIC
#GRAPH= nulgraph.o
#GRAPHLIB=
#---- Generic Unix -----------------------------------------------------------
# Remove #'s from following 3 lines for generic Unix with X-windows.
# Add -DOOGL to CFLAGS if you are using geomview.
# You might have to add something like -I/usr/X11R6/include to CFLAGS if
# there is a problem finding Xlib.h while compiling xgraph.c, and add
# -L/usr/X11R6/lib to GRAPHLIB.
#CFLAGS= -DGENERIC
#GRAPH= xgraph.o
#GRAPHLIB= -lX11
#some places might have -lX11-mit
#----- Linux OpenGL ----------------------------------------------------------
# Remove #'s from following 3 lines for LINUX with OpenGL GLUT graphics.
# The graphics are on a second thread, so pthreads are needed.
# NOTE: -DPTRHEADS is necessary with glutgraph.o.
#CFLAGS= -DLINUX -DOOGL -DPTHREADS
#GRAPH= glutgraph.o
#GRAPHLIB= -lGL -lGLU -lglut -lpthread
# NOTE: It has been reported to me that RedHat 9 needs the following line
# for GRAPHLIB, but earlier and later versions do okay with the GRAPHLIB
# line just above.
#GRAPHLIB= -lGL -lGLU -lglut -L/usr/X11R6/lib -lXi -lXmu -lpthread
#------ Linux Xwindows ------------------------------------------------------
# Remove #'s from following 3 lines for LINUX with crummy Xwindows graphics.
# You may have to modify the X11 lib path given here.
#CFLAGS= -DLINUX -DOOGL
#GRAPH= xgraph.o
#GRAPHLIB= -L/usr/X11R6/lib -lX11
#-------- cygwin --------------------------------------------------------------
# Remove #'s from the following three lines for cygwin.
#CFLAGS= -DLINUX -DOOGL -DPTHREADS
#GRAPH= glutgraph.o
#GRAPHLIB= -lglut -lglu32 -lopengl32 -lpthread
#------- Mac OSX -------------------------------------------------------------
# Remove #'s from following 5 lines for MAC OSX with OpenGL GLUT graphics.
#INC=/System/Library/Frameworks/GLUT.framework/Versions/A/Headers
#CFLAGS= -DLINUX -DPTHREADS -DOOGL -DMAC_OS_X -I$(INC)
#GRAPH= glutgraph.o
#GLDIR=/System/Library/Frameworks/OpenGL.framework/Libraries
#GRAPHLIB= -L$(GLDIR) -lGL -lGLU -lobjc -framework GLUT
#------- Sun Xwindows --------------------------------------------------------
# Remove #'s from following 3 lines for SUNs or SPARCSTATIONs with X-windows
# WARNING: If you use -O2 optimization, you may have to compile popfilm.c
# without optimization, because sun optimization may hang.
#CFLAGS= -DSUN -DOOGL -I/usr/openwin/include
#GRAPH= xgraph.o
#GRAPHLIB= -L/usr/openwin/lib -lX11
#------- 32-bint Solaris OpenGL ------------------------------------------------------
# 32-bit SOLARIS with GLUT. The GLUT graphics window runs in a separate
# thread; -DPTHREADS enables threads in Evolver source code, and -mt
# enables it in the Solaris cc compiler. For the gcc compiler, use -pthreads
# instead of -mt.
# You should check to see that the GLUTHOME directory listed below exists;
# it may be some other place on your machine. If you can't find it,
# download glut-3.7b.sparc_solaris.tar.gz from www.sun.com.
#GLUTHOME= /usr/local/sparc_solaris/glut-3.7
#INCLUDE= -I/usr/openwin/include -I$(GLUTHOME)/include
#CFLAGS= -DSUN -DOOGL -DGLUT -DPTHREADS -mt $(INCLUDE)
#GRAPH= glutgraph.o
#GRAPHLIB= -L/usr/openwin/lib -lX11 -L$(GLUTHOME)/lib/glut -lglut -lGL -lGLU -lXmu
#------- 64-bint Solaris OpenGL ------------------------------------------------------
# 64-bit SOLARIS with GLUT. Also see 32 bit comments above.
# You should check to see that the GLUTHOME directory listed below exists;
# it may be some other place on your machine. If you can't find it,
# download glut-3.7b.sparc_solaris_64.tar.gz from www.sun.com.
#GLUTHOME= /usr/local/sparc_solaris_64bit/glut-3.7
#INCLUDE= -I/usr/openwin/include -I$(GLUTHOME)/include
#CFLAGS= -DSUN -DOOGL -DGLUT -DPTHREADS -mt $(INCLUDE) -m64
#GRAPH= glutgraph.o
#GRAPHLIB= -L/usr/openwin/lib -lX11 -L$(GLUTHOME)/lib/glut -lglut -lGL -lGLU -lXmu
#Note on Solaris:
#SOLARISFLAGS= -L/usr/ucblib -lucb -R/usr/ucblib -lnsl -lsocket
#are needed for some programs on Solaris; but not this one -- they're poison
#for Evolver!
#-----------------------------------------------------------------------------
# Remove #'s from following 3 lines for DEC Alpha with X-windows
# Add -DOOGL to CFLAGS if you have the X version of geomview.
#CFLAGS= -DDECALPHA -O -Olimit 2000
#GRAPH= xgraph.o
#GRAPHLIB= -lX11
#-----------------------------------------------------------------------------
# IRIX 4, with old gl graphics
# Remove #'s from the following three lines for Iris workstations with
# geomview. Those with R4000 CPUs or above may add -mips2 to CFLAGS.
#CFLAGS = -DIRIS -DOOGL -O2 -Olimit 3000
#GRAPH= iriszgraph.o
#GRAPHLIB= -lgl_s -lmalloc -lc_s
#-----------------------------------------------------------------------------
# IRIX 5
# Remove #'s from the following three lines for Iris workstations with
# geomview. Those with R4000 CPUs or above may add -mips2 to CFLAGS.
#CFLAGS = -DIRIS -DOOGL -O2 -Olimit 3000
#GRAPH= xgraph.o
#GRAPHLIB= -lmalloc -lX11
#-----------------------------------------------------------------------------
# IRIX 5, parallel
# Remove #'s from the following three lines for Iris workstations with
# multiple processors and geomview. OK for single processors, too.
# Those with R4000 CPUs or above may add -mips2 to CFLAGS.
#CFLAGS = -DIRIS -DOOGL -DSGI_MULTI -O2 -Olimit 3000 -mips2
#GRAPH= xgraph.o
#GRAPHLIB= -lmalloc -lX11
#-----------------------------------------------------------------------------
# IRIX 6
# Remove #'s from the following three lines for Iris workstations with
# IRIX 6.x operating system. Add -DSGI_MULTI to CLFAGS if you
# have multiple processors.
#CFLAGS = -DIRIS -DOOGL -O2 -OPT:Olimit=10000
#GRAPH= xgraph.o
#GRAPHLIB= -lmalloc -lX11
#-----------------------------------------------------------------------------
# Remove #'s from following 3 lines for HP workstation
# Omit -Aa if you're using gcc
#CFLAGS= -Aa -D_HPUX_SOURCE -I/usr/include/X11R5
#GRAPH= xgraph.o
#GRAPHLIB= -L/usr/lib/X11R5 -lX11
#-----------------------------------------------------------------------------
# Remove #'s from following 3 lines for NeXTStep without screen graphics
# (see separate ftp archive evolver.next.tar.Z for graphics version)
#CFLAGS= -DNeXT
#GRAPH= nulgraph.o
#GRAPHLIB=
#-------------------End of system-specific options----------------------------
OBJ= calcforc.o variable.o trirevis.o stringl.o stringq.o model.o\
fixvol.o query.o matrix.o grapher.o painter.o filml.o filmq.o\
torvol.o lexinit.o graphgen.o modify.o userio.o boundary.o\
curtest.o display.o yexparse.o lexyy.o ytab.o hessian.o\
evaltree.o cnstrnt.o verpopst.o popfilm.o machine.o veravg.o \
pixgraph.o tmain.o tordup.o wulff.o help.o psgraph.o check.o \
utility.o skeleton.o storage.o dump.o iterate.o filgraph.o zoom.o\
softimag.o mvgraph.o diffuse.o sqcurve.o klein.o\
command.o hidim.o simplex.o metric.o torus.o quotient.o alice.o\
sdrv.o odrv.o userfunc.o kusner.o simequi2.o\
geomgraph.o symtable.o exprint.o quantity.o meanint.o mindeg.o\
dodecGroup.o registry.o khyp.o gauss.o knot1.o eval_all.o\
lexinit2.o evalmore.o knot2.o knot3.o teix.o sqcurve2.o\
hessian2.o hessian3.o method1.o method2.o method3.o bk.o\
method4.o method5.o eval_sec.o sqcurve3.o metis.o lagrange.o
evolver: makemark $(OBJ) $(GRAPH)
$(CC) $(CFLAGS) $(OBJ) $(GRAPH) $(GRAPHLIB) -o evolver -lm
# This is to get global dependencies on the main header files.
makemark: skeleton.h storage.h model.h web.h
if [[ -z "$(GRAPH)" ]] ; then (echo "ERROR: You need to uncomment your system's lines in Makefile.") ; fi
rm *.o || true
touch makemark
.c.o:
$(CC) $(CFLAGS) -c $<
# lexyy.c and ytab.c should only be remade when interface
# language is changed, which users shouldn't be touching.
#lexyy.c: datafile.lex express.h ytab.c lex.h
# lex datafile.lex
# sed '/#ident/d' t.c
# sed '/int \* p, int m/s/(int \* p, int m)/(p,m) int *p,m;/' lexyy.c
# rm lex.yy.c
#ytab.c: command.yac express.h
# yacc -d command.yac
# sed '/#ident/d' tmp.c
# sed '/malloc()/d' ytab.c
# rm tmp.c
# cp y.tab.h ytab.h
# rm y.tab.c y.tab.h
ytab.h: ytab.c
lexinit.o: lex.h lexinit.c express.h ytab.h
query.o: lex.h ytab.h query.c
evaltree.o: evaltree.c lex.h ytab.h express.h
eval_all.o: eval_all.c lex.h ytab.h express.h
eval_sec.o: eval_all.c lex.h ytab.h express.h
yexparse.o: yexparse.c lex.h ytab.h express.h
exprint.o: exprint.c lex.h ytab.h express.h
tmain.o: tmain.c include.h
evolver-2.30c.dfsg/src/filml.c 0000644 0001753 0001753 00000053506 11410765113 016475 0 ustar hazelsct hazelsct /*************************************************************
* This file is part of the Surface Evolver source code. *
* Programmer: Ken Brakke, brakke@susqu.edu *
*************************************************************/
/*********************************************************************
*
* file: filml.c
*
* Contents: Functions calculating energy, volume, and their
* gradients for the LINEAR SOAPFILM model.
*/
#include "include.h"
REAL wee_area = 0.0;
/*********************************************************************
*
* Function: facet_energy_l()
*
* Purpose: Calculates energy due to facet for LINEAR SOAPFILM.
* Also does facet quantity integrands.
*/
void facet_energy_l(f_id,mode)
facet_id f_id;
int mode; /* AREA_ONLY or ALL_ENERGY */
{
int i,j;
REAL side[FACET_EDGES][MAXCOORD];
REAL normal[MAXCOORD];
REAL wulff[MAXCOORD]; /* energy covector to area normal vector */
REAL energy;
body_id b_id;
REAL *x[FACET_VERTS];
REAL unwrap_x[FACET_VERTS][MAXCOORD];
REAL z[FACET_VERTS]; /* for calculating average z*z */
REAL zz; /* for average z*z, for gravity */
REAL u; /* gravitational energy */
facetedge_id fe_id;
vertex_id v_id[FACET_VERTS];
REAL ss,st,tt;
REAL det;
#ifdef THREADS
struct thread_data *data = GET_THREAD_DATA;
#endif
int_val = ordinal(get_original(f_id))+1; /* for eval of file parameters */
/* get side vectors */
fe_id = get_facet_fe(f_id);
for ( i = 0 ; i < FACET_EDGES ; i++ )
{
v_id[i] = get_fe_tailv(fe_id);
x[i] = unwrap_x[i];
fe_id = get_next_edge(fe_id);
}
get_facet_verts(f_id,x,NULL); /* in tail order */
for ( i = 0 ; i < FACET_EDGES ; i++ )
{ int ii = (i+1)%FACET_EDGES;
for ( j = 0 ; j < SDIM ; j++ )
side[i][j] = x[ii][j] - x[i][j];
z[i] = x[i][2];
}
if ( web.metric_flag )
{ if ( klein_metric_flag )
energy = klein_area(x);
else energy = simplex_energy_metric(v_id,x);
set_facet_area(f_id,energy);
goto skip_from_metric;
}
/* calculate surface tension energy */
ss = SDIM_dot(side[0],side[0]);
st = SDIM_dot(side[0],side[1]);
tt = SDIM_dot(side[1],side[1]);
det = ss*tt-st*st;
if ( det > 0.0 ) energy = sqrt(det)/2;
else energy = 0.0;
set_facet_area(f_id,energy);
if ( mode == AREA_ONLY ) return;
if ( web.wulff_flag )
{
/* calculate normal */
cross_prod(side[0],side[1],normal);
(*get_wulff)(normal,wulff);
energy = SDIM_dot(wulff,normal)/2;
}
/* do square curvature if wanted */
if ( ((square_curvature_flag | mean_curv_int_flag) & EVALUATE )
&& !kusner_flag && !conf_edge_curv_flag )
sqcurve_energy(v_id,side);
skip_from_metric:
#ifdef THREADS
if ( threadflag )
data->total_area = data->total_area + energy; /* Borland C bug */
else
#endif
binary_tree_add(web.total_area_addends,energy);
if ( get_fattr(f_id) & DENSITY )
energy = energy * get_facet_density(f_id); /* Borland C bug */
/* add gravitational energy, vector potential z*z/2*k */
if ( web.gravflag && !(get_fattr(f_id) & NONCONTENT) )
{
zz = (z[0]*z[0]+z[1]*z[1]+z[2]*z[2]+z[0]*z[1]+z[1]*z[2]+z[0]*z[2])/6;
u = zz*(side[0][0]*side[1][1]-side[0][1]*side[1][0])/2/2;
/* half for area, half from potential */
b_id = get_facet_body(f_id);
if ( valid_id(b_id) )
energy += u*get_body_density(b_id)*web.grav_const;
b_id = get_facet_body(facet_inverse(f_id));
if ( valid_id(b_id) )
energy -= u*get_body_density(b_id)*web.grav_const;
}
#ifdef THREADS
if ( threadflag )
data->total_energy = data->total_energy + energy; /* Borland C bug */
else
#endif
binary_tree_add(web.total_energy_addends,energy);
} /* end facet_energy_l() */
/************************************************************************
*
* Function: facet_force_l()
*
* Purpose: Calculates all forces on control points due to facet and
* accumulates them at each control point.
*/
void facet_force_l(f_id)
facet_id f_id;
{
REAL side[FACET_EDGES][MAXCOORD];
REAL normal[MAXCOORD];
REAL wulff[MAXCOORD]; /* area vector covector for energy */
REAL temp[MAXCOORD];
int i,j;
REAL area;
facetedge_id fe_id;
REAL *x[FACET_VERTS];
REAL z[FACET_VERTS]; /* for gravitational forces */
body_id b_id;
REAL density = get_facet_density(f_id);
vertex_id v_id[FACET_VERTS];
edge_id e_id[FACET_EDGES];
REAL unwrap_x[FACET_VERTS][MAXCOORD];
WRAPTYPE wraps[FACET_VERTS];
REAL forces[FACET_VERTS][MAXCOORD]; /* total forces from this facet */
REAL *forceptr[FACET_VERTS]; /* pointers to forces */
REAL ss,st,tt;
memset((char*)forces,0,sizeof(forces)); /* set to 0 */
int_val = ordinal(get_original(f_id))+1; /* for eval of file parameters */
/* get side vectors */
fe_id = get_facet_fe(f_id);
for ( i = 0 ; i < FACET_EDGES ; i++ )
{
e_id[i] = get_fe_edge(fe_id);
v_id[i] = get_edge_tailv(e_id[i]);
x[i] = unwrap_x[i];
forceptr[i] = forces[i];
fe_id = get_next_edge(fe_id);
}
get_facet_verts(f_id,x,wraps); /* verts in tail order */
for ( i = 0 ; i < FACET_EDGES ; i++ )
{ int ii = (i+1)%FACET_EDGES;
for ( j = 0 ; j < SDIM ; j++ )
side[i][j] = x[ii][j] - x[i][j];
z[i] = x[i][2];
}
if ( web.metric_flag )
{ if ( klein_metric_flag )
{ klein_area_grad(x,forceptr);
for ( i = 0 ; i < FACET_VERTS ; i++ )
for ( j = 0 ; j < SDIM ; j++ )
forceptr[i][j] *= density;
area = klein_area(x);
}
else
{ simplex_force_metric(v_id,x,density,forceptr);
area = simplex_energy_metric(v_id,x);
}
goto end_euclidean;
}
if ( ((square_curvature_flag | mean_curv_int_flag) & EVALUATE)
&& !kusner_flag && !conf_edge_curv_flag )
sqcurve_force(v_id,e_id,side);
/* calculate area */
ss = SDIM_dot(side[0],side[0]);
st = SDIM_dot(side[0],side[1]);
tt = SDIM_dot(side[1],side[1]);
area = ss*tt-st*st;
if ( area < 0.0 ) area = 0.0; /* stupid inaccurate computers! */
area = sqrt(area)/2;
set_facet_area(f_id,area);
/* an error check, and accommodation for possibly deliberately
degenerate triangles on boundary */
if ( area <= wee_area )
{ facetedge_id ffe;
ffe = fe_id;
sprintf(errmsg,"WARNING! Zero area for facet %s.\n",ELNAME(f_id));
outstring(errmsg);
if ( itdebug )
{
outstring("Facet-edges and side vectors: \n");
for ( i = 0 ; i < FACET_EDGES ; i++, ffe = get_next_edge(ffe) )
{
sprintf(msg," %8lX %18.15f %18.15f %18.15f\n",ffe,
(DOUBLE)side[i][0],(DOUBLE)side[i][1],(DOUBLE)side[i][2]);
outstring(msg);
}
prompt("Hit RETURN to continue.",msg,msgmax);
}
return;
}
/* get energy covector */
if ( web.wulff_flag )
{
/* calculate normal */
cross_prod(side[0],side[1],normal);
(*get_wulff)(normal,wulff);
if ( get_fattr(f_id) & DENSITY )
for ( i = 0 ; i < SDIM ; i++ )
wulff[i] *= density;
/* force on each vertex */
for ( i = 0 ; i < FACET_VERTS ; i++ ) /* vertex loop */
{ int k;
j = (i+1)%FACET_EDGES; /* opposite side */
cross_prod(side[j],wulff,temp);
for ( k = 0 ; k < SDIM ; k++ ) forces[i][k] += temp[k]/2;
}
}
else
{ REAL coeff = density/4/area;
int k;
for ( k = 0 ; k < SDIM ; k++ )
{ forces[0][k] += coeff*(side[0][k]*tt - st*side[1][k]);
forces[1][k] -= coeff*(side[0][k]*tt - st*side[1][k]);
forces[1][k] += coeff*(ss*side[1][k] - st*side[0][k]);
forces[2][k] -= coeff*(ss*side[1][k] - st*side[0][k]);
}
}
/* gravity forces, negative of gravity energy gradient */
if ( web.gravflag && !(get_fattr(f_id) & NONCONTENT) )
{ REAL zz; /* average z*z */
REAL gdensity; /* net density difference of bodies across facet */
REAL normz; /* facet normal component in z direction */
zz = (z[0]*z[0]+z[1]*z[1]+z[2]*z[2]+z[0]*z[1]+z[1]*z[2]+z[0]*z[2])/6;
b_id = get_facet_body(f_id);
gdensity = 0.0;
if ( valid_id(b_id) )
gdensity += get_body_density(b_id);
b_id = get_facet_body(facet_inverse(f_id));
if ( valid_id(b_id) )
gdensity -= get_body_density(b_id);
normz = side[0][0]*side[1][1] - side[0][1]*side[1][0];
for ( i = 0 ; i < FACET_VERTS ; i++ ) /* vertex loop */
{
j = (i+1)%FACET_EDGES; /* opposite side */
forces[i][0] += web.grav_const*gdensity*side[j][1]*zz/4;
forces[i][1] -= web.grav_const*gdensity*side[j][0]*zz/4;
forces[i][2] -= web.grav_const*gdensity*normz*(z[i]+z[0]+z[1]+z[2])/24;
}
}
end_euclidean:
/* accumulate star area around each vertex and edge */
fe_id = get_facet_fe(f_id);
for ( i = 0 ; i < FACET_VERTS ; i++ ) /* vertex loop */
{ edge_id ee_id;
vertex_id vv_id;
ee_id = get_fe_edge(fe_id);
vv_id = get_edge_headv(ee_id);
add_vertex_star(vv_id,area);
add_edge_star(ee_id,area);
fe_id = get_next_edge(fe_id);
}
/* add to totals, unwrapping if necessary */
for ( i = 0 ; i < FACET_VERTS ; i++ ) /* vertex loop */
{ REAL *force;
REAL wforce[MAXCOORD]; /* unwrapped forces */
force = get_force(v_id[i]);
if ( web.symmetry_flag )
{ (*sym_form_pullback)(get_coord(v_id[i]),wforce,forces[i],wraps[i]);
for ( j = 0 ; j < SDIM ; j++ )
force[j] += wforce[j];
}
else
{ for ( j = 0 ; j < SDIM ; j++ )
force[j] += forces[i][j];
}
}
} /* end facet_force_l() */
/**********************************************************************
*
* Function: facet_volume_l()
*
* Purpose: Find triangle's contribution to volumes of neighboring bodies.
* Volumes with respect to origin are calculated for each
* face, and then oriented contributions added for each body.
*/
void facet_volume_l(f_id)
facet_id f_id;
{
body_id b_id0,b_id1;
facetedge_id fe_id;
REAL vol;
if ( get_fattr(f_id) & NONCONTENT ) return;
int_val = ordinal(get_original(f_id))+1; /* for eval of file parameters */
b_id0 = get_facet_body(f_id);
b_id1 = get_facet_body(facet_inverse(f_id));
if ( !valid_id(b_id0) && !valid_id(b_id1) ) return;
if ( web.symmetric_content )
{ vertex_id v1,v2,v3;
facetedge_id next_fe;
fe_id = get_facet_fe(f_id);
next_fe = get_next_edge(fe_id);
v1 = get_fe_tailv(fe_id);
v2 = get_fe_headv(fe_id);
v3 = get_fe_headv(next_fe);
vol = triple_prod(get_coord(v1), get_coord(v2), get_coord(v3))/6;
}
else
{ MAT2D(x,MAXCOORD,MAXCOORD);
get_facet_verts(f_id,x,NULL);
vol = (x[0][2]+x[1][2]+x[2][2])/6*
((x[1][0]-x[0][0])*(x[2][1]-x[0][1])-(x[1][1]-x[0][1])*(x[2][0]-x[0][0]));
}
/* add to body volumes */
if ( valid_id(b_id0) )
add_body_volume(b_id0,vol);
if ( valid_id(b_id1) )
add_body_volume(b_id1,-vol);
} /* end facet_volume_l() */
/******************************************************************
*
* Function: film_grad_l()
*
* Purpose: Compute volume gradients for vertices on facets.
* Also fixed quantity gradients.
*/
#define NEWTORVOL
void film_grad_l()
{
body_id bi_id; /* identifier for body i */
body_id bj_id; /* identifier for body j */
facetedge_id fe;
vertex_id v_id;
facet_id f_id;
facetedge_id fe_id;
int i,k;
volgrad *vgptr;
REAL z;
REAL side[FACET_EDGES][MAXCOORD];
REAL normal[MAXCOORD];
REAL *x[FACET_VERTS]; /* coordinates of vertices */
REAL unwrap_x[FACET_VERTS][MAXCOORD];
#ifdef NEWTORVOL
struct qinfo f_info; /* for calling q_facet_torus_volume */
if ( web.torus_flag )
q_info_init(&f_info,METHOD_GRADIENT);
#endif
if ( sym_flags & NEED_FORM_UNWRAPPING )
kb_error(1035,"Have to do convert_to_quantities with this symmetry group.\n",RECOVERABLE);
FOR_ALL_FACETS(f_id)
{
WRAPTYPE wraps[3];
int_val = ordinal(get_original(f_id))+1; /* for eval of file parameters */
bi_id = get_facet_body(f_id);
bj_id = get_facet_body(facet_inverse(f_id));
if ( (!valid_id(bi_id) || !(get_battr(bi_id) & (FIXEDVOL|PRESSURE)) )
&& (!valid_id(bj_id) || !(get_battr(bj_id) & (FIXEDVOL|PRESSURE)) ) )
continue;
if ( web.torus_flag )
{
#ifdef NEWTORVOL
int n;
vertex_id v_ids[FACET_EDGES];
/* get basic info */
fe = get_facet_fe(f_id);
for ( i = 0 ; i < FACET_EDGES ; i ++ )
{ v_ids[i] = get_fe_tailv(fe);
fe = get_next_edge(fe);
}
f_info.id = f_id;
q_facet_setup(NULL,&f_info,NEED_SIDE|TORUS_MODULO_MUNGE|ORIENTABLE_METHOD);
q_facet_torus_volume_grad(&f_info);
if ( valid_id(bi_id) && (get_battr(bi_id) & (FIXEDVOL|PRESSURE)) )
for ( i = 0 ; i < FACET_VERTS ; i++ )
{ vgptr = get_bv_new_vgrad(get_body_fixnum(bi_id),v_ids[i]);
vgptr->bb_id = bi_id;
for ( n = 0 ; n < SDIM ; n++ )
vgptr->grad[n] += f_info.grad[i][n];
}
if ( valid_id(bj_id) && (get_battr(bj_id) & (FIXEDVOL|PRESSURE)) )
for ( i = 0 ; i < FACET_VERTS ; i++ )
{ vgptr = get_bv_new_vgrad(get_body_fixnum(bj_id),v_ids[i]);
vgptr->bb_id = bj_id;
for ( n = 0 ; n < SDIM ; n++ )
vgptr->grad[n] -= f_info.grad[i][n];
}
#else
/* kludge copy from torvol_project, so could ditch torvol_project */
REAL *v[FACET_VERTS]; /* pointers to three vertex coordinates */
int j;
REAL adj[FACET_EDGES][MAXCOORD]; /* torus wrap adjustments for edge */
vertex_id v_ids[FACET_VERTS];
int n;
REAL g[MAXCOORD];
/* get basic info */
fe = get_facet_fe(f_id);
for ( i = 0 ; i < FACET_EDGES ; i ++ )
{
v_ids[i] = get_fe_tailv(fe);
v[i] = get_coord(get_fe_tailv(fe));
get_edge_adjust(get_fe_edge(fe),adj[i]);
fe = get_next_edge(fe);
}
for ( i = 0 ; i < FACET_EDGES ; i++ )
{
int m;
REAL ga[MAXCOORD],gb[MAXCOORD],gc[MAXCOORD],gd[MAXCOORD],
ge[MAXCOORD],gf[MAXCOORD]; /* gradient parts */
j = (i+1)%FACET_EDGES;
k = (i+2)%FACET_EDGES;
/* basic tetrahedron */
cross_prod(v[j],v[k],ga);
/* torus wrap corrections */
/* two-vertex term */
cross_prod(adj[j],v[j],gb); /* - */
cross_prod(adj[i],v[k],gc); /* + */
cross_prod(adj[k],v[j],gd); /* + */
cross_prod(adj[j],v[k],ge); /* - */
/* one-vertex term */
cross_prod(adj[k],adj[i],gf);
/* add parts to existing gradient */
for ( m = 0 ; m < SDIM ; m++ )
g[m] = (ga[m] + (-gb[m]+gc[m]+gd[m]-ge[m])/2 + gf[m])/6;
if ( valid_id(bi_id) && (get_battr(bi_id) & (FIXEDVOL|PRESSURE)) )
{
vgptr = get_bv_new_vgrad(get_body_fixnum(bi_id),v_ids[i]);
vgptr->bb_id = bi_id;
for ( n = 0 ; n < SDIM ; n++ )
vgptr->grad[n] += g[n];
}
if ( valid_id(bj_id) && (get_battr(bj_id) & (FIXEDVOL|PRESSURE)) )
{
vgptr = get_bv_new_vgrad(get_body_fixnum(bj_id),v_ids[i]);
vgptr->bb_id = bj_id;
for ( n = 0 ; n < SDIM ; n++ )
vgptr->grad[n] -= g[n];
}
}
#endif
}
else
{
vertex_id v[3];
/* get side vectors */
fe_id = get_facet_fe(f_id);
for ( i = 0 ; i < FACET_EDGES ; i++ )
{
get_fe_side(fe_id,side[i]);
v[i] = get_fe_headv(fe_id);
x[i] = get_coord(v[i]);
fe_id = get_next_edge(fe_id);
}
if ( web.symmetry_flag )
{
for ( i = 0 ; i < FACET_VERTS ; i++ ) x[i] = unwrap_x[i];
get_facet_verts(f_id,x,wraps);
/* have to readjust indexing for agreement with nonsym way..
kludge, but don't want to risk massive changes */
for ( i = 0 ; i < FACET_VERTS ; i++ ) x[i] = unwrap_x[(i+1)%3];
for ( i = 0 ; i < SDIM ; i++ )
{ side[0][i] = x[0][i] - x[2][i];
side[1][i] = x[1][i] - x[0][i];
side[2][i] = x[2][i] - x[1][i];
}
}
if ( web.symmetric_content )
{
/* do each of the three vertices */
fe = get_facet_fe(f_id);
for ( k = 0 ; k < FACET_VERTS ; k++, fe = get_next_edge(fe) )
{
fe_id = get_next_edge(fe);
v_id = get_fe_headv(fe_id);
if ( get_vattr(v_id) & FIXED ) continue;
cross_prod(get_coord(get_fe_tailv(fe)),
get_coord(get_fe_headv(fe)),normal);
if ( valid_id(bi_id) && (get_battr(bi_id) & (PRESSURE|FIXEDVOL)) )
{
vgptr = get_bv_new_vgrad(get_body_fixnum(bi_id),v_id);
vgptr->bb_id = bi_id;
for ( i = 0 ; i < SDIM ; i++ )
vgptr->grad[i] += normal[i]/6.0;
}
if ( valid_id(bj_id) && (get_battr(bj_id) & (PRESSURE|FIXEDVOL)) )
{
vgptr = get_bv_new_vgrad(get_body_fixnum(bj_id),v_id);
vgptr->bb_id = bj_id;
for ( i = 0 ; i < SDIM ; i++ )
vgptr->grad[i] -= normal[i]/6.0;
}
}
}
else
{ /* content from integrating z dx dy */
/* get centroid z (divide by 3 later) */
for ( i = 0,z = 0.0; i < FACET_EDGES ; i++ ) z += x[i][2];
/* calculate normal */
cross_prod(side[0],side[1],normal);
/* now do each of the three vertices */
fe = get_facet_fe(f_id);
for ( k = 0 ; k < FACET_VERTS ; k++, fe = get_next_edge(fe) )
{
fe_id = get_next_edge(fe);
v_id = get_fe_headv(fe_id);
if ( get_vattr(v_id) & FIXED ) continue;
if ( valid_id(bi_id) && (get_battr(bi_id) & (PRESSURE|FIXEDVOL)) )
{
vgptr = get_bv_new_vgrad(get_body_fixnum(bi_id),v_id);
vgptr->bb_id = bi_id;
vgptr->grad[0] += -side[k][1]*z/6.0;
vgptr->grad[1] += side[k][0]*z/6.0;
vgptr->grad[2] += normal[2]/6.0;
}
if ( valid_id(bj_id) && (get_battr(bj_id) & (PRESSURE|FIXEDVOL)) )
{
vgptr = get_bv_new_vgrad(get_body_fixnum(bj_id),v_id);
vgptr->bb_id = bj_id;
vgptr->grad[0] -= -side[k][1]*z/6.0;
vgptr->grad[1] -= side[k][0]*z/6.0;
vgptr->grad[2] -= normal[2]/6.0;
}
}
}
} /* end torus/nontorus */
} /* end facet loop */
#ifdef NEWTORVOL
if ( web.torus_flag )
q_info_free(&f_info);
#endif
} /* end film_grad_l() */
/*******************************************************************
*
* Function: film_constr_grad()
*
* Purpose: Add cell volume gradients due to constraint integrals.
* And quantity integrals.
*/
void film_constr_grad()
{
edge_id e_id;
REAL side[MAXCOORD];
REAL tgrad[MAXCOORD];
REAL hgrad[MAXCOORD];
REAL grad;
int i,j,k,m,sign,bodysign=0;
REAL green[MAXCOORD];
REAL green_deriv[MAXCOORD][MAXCOORD];
REAL midpt[MAXCOORD];
REAL *tcoord,*hcoord;
struct constraint *constr;
vertex_id headv,tailv;
facetedge_id fe,first_fe;
FOR_ALL_EDGES(e_id)
{
struct volgrad *vgptri;
facet_id f_id;
ATTR attr = get_eattr(e_id);
conmap_t *conmap = get_e_constraint_map(e_id); /* only hit constraints */
if ( attr & FIXED ) continue;
if ( !(attr & CONSTRAINT) ) continue;
headv = get_edge_headv(e_id);
tailv = get_edge_tailv(e_id);
tcoord = get_coord(tailv);
hcoord = get_coord(headv);
int_val = ordinal(get_original(e_id))+1; /* for eval of file parameters */
for ( j = 0 ; j < SDIM ; j++ )
side[j] = hcoord[j] - tcoord[j];
if ( !(attr & BDRY_CONTENT) ) continue;
if ( web.modeltype == QUADRATIC )
{ constr_vol_grad_q(e_id);
continue;
}
else if ( web.modeltype == LAGRANGE )
kb_error(1036,"constr_vol_grad(): Cannot do LAGRANGE model.\n",RECOVERABLE);
if ( attr & NEGBOUNDARY ) sign = -1;
else sign = 1;
if ( inverted(e_id) ) sign = -sign;
for ( i = 0 ; i < SDIM ; i++ )
tgrad[i] = hgrad[i] = 0.0;
for ( j = 1 ; j <= (int)conmap[0] ; j++ )
{
constr = get_constraint(conmap[j]);
if ( constr->compcount != SDIM ) continue;
if ( !(constr->attr & CON_CONTENT) ) continue;
for ( m = 0 ; m < gauss1D_num ; m++ )
{
for ( i = 0 ; i < SDIM ; i++ )
midpt[i] = gauss1Dpt[m]*hcoord[i] + (1 - gauss1Dpt[m])*tcoord[i];
for ( i = 0 ; i < SDIM ; i++ )
eval_all(constr->convect[i],midpt,SDIM,&green[i],
green_deriv[i],e_id);
for ( i = 0 ; i < SDIM ; i++ )
{
for ( k = 0,grad = 0.0 ; k < SDIM ; k++ )
grad += side[k]*green_deriv[k][i];
tgrad[i] += sign*gauss1Dwt[m]*((1-gauss1Dpt[m])*grad - green[i]);
hgrad[i] += sign*gauss1Dwt[m]*(gauss1Dpt[m]*grad + green[i]);
}
}
}
fe = first_fe = get_edge_fe(e_id);
if ( valid_id(fe) ) do
{ f_id = get_fe_facet(fe);
vgptri = get_vertex_vgrad(tailv);
for ( ; vgptri ; vgptri = vgptri->chain )
{
if ( !valid_id(vgptri->bb_id) ) continue; /* skip quantities */
if ( !equal_id(get_facet_body(f_id),vgptri->bb_id) )
{ if ( !equal_id(get_facet_body(inverse_id(f_id)),vgptri->bb_id) )
continue;
else bodysign = -sign;
}
else bodysign = sign;
for ( i = 0 ; i < SDIM ; i++ )
vgptri->grad[i] += bodysign*tgrad[i];
}
vgptri = get_vertex_vgrad(headv);
for ( ; vgptri ; vgptri = vgptri->chain )
{
if ( !valid_id(vgptri->bb_id) ) continue; /* skip quantities */
if ( !equal_id(get_facet_body(f_id),vgptri->bb_id) )
{ if ( !equal_id(get_facet_body(inverse_id(f_id)),vgptri->bb_id) )
continue;
else bodysign = -sign;
}
else bodysign = sign;
for ( i = 0 ; i < SDIM ; i++ )
vgptri->grad[i] += bodysign*hgrad[i];
}
fe = get_next_facet(fe);
} while ( valid_id(fe) && !equal_id(fe,first_fe) );
}
} /* end film_constr_grad() */
evolver-2.30c.dfsg/src/curtest.c 0000644 0001753 0001753 00000020157 11410765113 017057 0 ustar hazelsct hazelsct /*************************************************************
* This file is part of the Surface Evolver source code. *
* Programmer: Ken Brakke, brakke@susqu.edu *
*************************************************************/
/*********************************************************************
*
* File: curtest.c
*
* Purpose: Test curvature of quadratic soapfilms to see if
* the curvature is monotone.
*
*/
#include "include.h"
/*********************************************************************
*
* Function: curtest()
*
* Purpose: Overall control of curvature testing.
*
*/
void curtest()
{
facet_id f_id;
edge_id e_id;
int retval;
int edgetally[3],facettally[3];
int i;
if ( web.modeltype != QUADRATIC )
{ outstring("Cannot only do curvature sign test on QUADRATIC model.\n");
return;
}
for ( i = 0 ; i < 3; i++ )
edgetally[i] = facettally[i] = 0;
FOR_ALL_FACETS(f_id)
{
retval = curtest_facet(f_id);
if ( retval < 0 ) facettally[0]++;
else if ( retval == 0 ) facettally[1]++;
else facettally[2]++;
}
FOR_ALL_EDGES(e_id)
{
facetedge_id fe1,fe2;
fe1 = get_edge_fe(e_id);
if ( !valid_id(fe1) ) continue;
/* ensure orientation lines up with original definition */
if ( inverted(get_fe_facet(fe1)) )
{ invert(e_id);
invert(fe1);
}
fe2 = get_next_facet(fe1);
if ( equal_id(fe1,fe2) ) continue; /* only 1 facet on edge */
if ( !equal_id(fe1,get_next_facet(fe2)) ) continue; /* more than 2 */
retval = curtest_edge(e_id,fe1,fe2);
if ( retval < 0 ) edgetally[0]++;
else if ( retval == 0 ) edgetally[1]++;
else edgetally[2]++;
}
/* report results */
sprintf(msg,"\nPositive curvature edges: %6d\n",edgetally[2]);
outstring(msg);
sprintf(msg,"Negative curvature edges: %6d\n",edgetally[0]);
outstring(msg);
sprintf(msg,"Mixed curvature edges: %6d\n",edgetally[1]);
outstring(msg);
sprintf(msg,"Positive curvature facets: %6d\n",facettally[2]);
outstring(msg);
sprintf(msg,"Negative curvature facets: %6d\n",facettally[0]);
outstring(msg);
sprintf(msg,"Mixed curvature facets: %6d\n\n",facettally[1]);
outstring(msg);
}
/*******************************************************************
*
* Function: curtest_edge()
*
* Purpose: See if two facets meet along an edge with monotone
* meeting angle.
*
* Return: Sign of (normal 1) x (normal 2) . (edge)
* +1 for all positive
* -1 for all negative
* 0 otherwise
*/
/* evaluation points of cubic angle polynomial */
REAL uu[4] = {0.0, 0.7, 1.3, 2.0}; /* parameter along edge, 0 < u < 2 */
/* coefficients for finding polynomial coefficients */
REAL b1 = 0.3, b2 = 0.09, b3 = 0.027, denom = 1.0/(1 - 0.09);
int curtest_edge(e_id,fe_1,fe_2)
edge_id e_id; /* the edge */
facetedge_id fe_1,fe_2; /* link edge with facets */
{
REAL *x[2][FACET_CTRL]; /* pointers to sets of vertices, starting along edge */
REAL h[4]; /* values of curvature polynomial */
REAL a[4]; /* polynomial coefficients */
int i,j,k;
int sign; /* return value */
REAL tu[MAXCOORD]; /* common tangent along edge */
REAL tv[2][MAXCOORD]; /* the other tangent for each face */
REAL discr; /* quadratic formula discriminant */
REAL r[2]; /* quadratic roots */
REAL val; /* curvature values */
/* gather vertex coordinates */
x[0][0] = x[1][0] = get_coord(get_edge_tailv(e_id));
x[0][1] = x[1][1] = get_coord(get_edge_midv(e_id));
x[0][2] = x[1][2] = get_coord(get_edge_headv(e_id));
x[0][3] = get_coord(get_fe_midv(get_next_edge(fe_1)));
x[1][3] = get_coord(get_fe_midv(get_next_edge(fe_2)));
x[0][4] = get_coord(get_fe_headv(get_next_edge(fe_1)));
x[1][4] = get_coord(get_fe_headv(get_next_edge(fe_2)));
x[0][5] = get_coord(get_fe_midv(get_prev_edge(fe_1)));
x[1][5] = get_coord(get_fe_midv(get_prev_edge(fe_2)));
/* calculate test triple product at 4 points (it being cubic) */
for ( i = 0 ; i < 4 ; i++ )
{
/* edge tangent */
for ( j = 0 ; j < SDIM ; j++ )
{
tu[j] = x[0][0][j]*(uu[i] - 1.5) + 2*x[0][1][j]*(1 - uu[i])
+ x[0][2][j]*(uu[i] - 0.5);
for ( k = 0 ; k < 2 ; k++ )
tv[k][j] = x[k][0][j]*(uu[i] - 1.5) - x[k][1][j]*uu[i]
+ x[k][3][j]*uu[i] - 0.5*x[k][4][j]
+ x[k][5][j]*(2.0 - uu[i]);
}
h[i] = triple_prod(tv[0],tv[1],tu);
}
/* see if signs at endpoints same or opposite */
if ( (h[0] > 0.0) != (h[3] > 0.0) ) return 0;
if ( h[0] > 0.0 ) sign = 1;
else sign = -1;
/* get polynomial coefficients */
/* (remapping to points -1, -0.3, 0.3, 1) */
a[0] = (h[1] + h[2] - b2*(h[0] + h[3]))/denom;
a[1] = (h[2] - h[1] - b3*(h[3] - h[0]))/denom;
a[2] = (h[0] - h[2] + h[3] - h[1])/denom;
a[3] = (b1*(h[3] - h[0]) - (h[2] - h[1]))/denom;
/* now decide on sign of cubic polynomial fitting h[] */
/* find max and min points */
discr = a[2]*a[2] - 3*a[1]*a[3];
if ( discr <= 0.0 ) return sign; /* no critical points */
discr = sqrt(discr);
r[0] = (-a[2] + discr)/3/a[3];
r[1] = (-a[2] - discr)/3/a[3];
for ( i = 0 ; i < 2 ; i++ )
{ if ( (r[i] < -1.0) || (r[i] > 1.0) ) continue;
val = a[0] + r[i]*(a[1] + r[i]*(a[2] + r[i]*a[3]));
if ( (val > 0.0) != (h[0] > 0.0) ) return 0;
}
return sign;
}
/*******************************************************************
*
* Function: curtest_facet()
*
* Purpose: See if a facet has constant sign mean curvature.
*
* Return: Sign of curvature with respect to oriented facet:
* +1 for all positive
* -1 for all negative
* 0 otherwise
*/
int curtest_facet(f_id)
facet_id f_id;
{
REAL *x[FACET_CTRL]; /* pointers to coordinates */
facetedge_id fe;
REAL tt[2][2][MAXCOORD]; /* position second partials */
REAL tutu,tvtv,tutv,t[2][MAXCOORD];
int i,j,k,m;
int sign = 0; /* return value 1 or -1 at end if all same curvature */
REAL u,v;
REAL vv[MAXCOORD]; /* first variation vector, sort of */
REAL h; /* curvature at test point */
/* gather vertices */
fe = get_facet_fe(f_id);
x[0] = get_coord(get_fe_tailv(fe));
x[1] = get_coord(get_fe_midv(fe));
fe = get_next_edge(fe);
x[2] = get_coord(get_fe_tailv(fe));
x[3] = get_coord(get_fe_midv(fe));
fe = get_next_edge(fe);
x[4] = get_coord(get_fe_tailv(fe));
x[5] = get_coord(get_fe_midv(fe));
/* calculate position second partials (independent of u,v) */
for ( i = 0 ; i < 2 ; i++ )
for ( j = 0 ; j < 2 ; j++ )
for ( k = 0 ; k < SDIM ; k++ )
{ tt[i][j][k] = 0.0;
for ( m = 0 ; m < FACET_CTRL ; m++ )
tt[i][j][k] += poly2partial[m][i][j]*x[m][k];
}
/* loop for sampling curvature */
for ( u = 0.0 ; u < 2.00001 ; u += 0.4 )
for ( v = 0.0 ; u+v < 2.00001 ; v += 0.4 )
{
/* inner loop does test at one point */
/* calculate tangents */
for ( i = 0 ; i < 2 ; i++ )
for ( k = 0 ; k < SDIM ; k++ )
{ t[i][k] = 0.0;
for ( m = 0 ; m < FACET_CTRL ; m++ )
t[i][k] += intpoly6part(m,i,u,v)*x[m][k];
}
/* tangent dot products */
tutu = SDIM_dot(t[0],t[0]);
tutv = SDIM_dot(t[0],t[1]);
tvtv = SDIM_dot(t[1],t[1]);
/* assemble variation vector */
for ( k = 0 ; k < SDIM ; k++ )
vv[k] = 2*tutv*tt[0][1][k] - tutu*tt[1][1][k] - tvtv*tt[0][0][k];
/* test normal component */
h = triple_prod(t[0],t[1],vv);
if ( h > 0.0 )
{ if ( sign == 0 ) sign = 1;
else if ( sign < 0 ) return 0;
}
else
if ( sign == 0 ) sign = -1;
else if ( sign > 0 ) return 0;
/* end inner loop */
}
return sign;
}
evolver-2.30c.dfsg/src/oglgraph.c 0000644 0001753 0001753 00000162123 11410765113 017171 0 ustar hazelsct hazelsct /*********************************************************************
*
* File: oglgraph.c
*
* Contents: OpenGL display for Surface Evolver
* For OpenGL Version 1.1
*/
/* This runs in a separate thread from the main program, so it avoids
calling kb_error, since that would longjump to the wrong place.
Except for WARNINGS, which are OK since kb_error just returns.
*/
/* Some timings in various OpenGL drawing modes:
(done with cat.fe and gtime.cmd)(list, arrays exclude setup time)
(done in 'u' mode for 10 drawings; time for one reported here)
(flat shading for no arrays; doesn't matter for others)
facets edges no arrays display list arrays indexed arrays strips
6144 9132 0.2224 0.1500 0.1021 0.0691 0.0420
24576 37056 0.8552 0.5740 0.3846 0.2544 0.1292
98304 147840 3.4059 1.4932 1.0154 0.4888
98304 0 1.6513 0.6630 0.5208 0.5348 0.2223
393216 0 7.8273 3.2527 2.1140 2.1827 0.8720
To get a sense of the set-up times, here are recalc times,
flat shading except for strips.
facets edges no arrays display list arrays indexed arrays strips
6144 9132 0.32 1.2319 0.3796 0.5558 0.9143
24576 37056 0.9164 11.1961 1.0064 1.6804 2.9993
98304 147840 3.6503 4.2781 6.9260 12.5481
On transforms, using srol.8.fe
Transforms facets edges arrays indexed arrays strips
24 196608 297216 3.3058 2.2122 1.2307
A little slower than one would expect, maybe due to normal flipping??
Or memory caching? But at least set-up is fast.
*/
#undef DOUBLE
#if defined(WIN32) || defined(_WIN32)
#undef FIXED
#include
HWND hwnd;
#else
#include
#define CALLBACK
#endif
#include "include.h"
static char opengl_version[20]; /* from glGetString */
int close_flag = 0; /* whether close_show has been done */
vertex_id focus_vertex_id; /* rotate and zoom focus */
static float rgba[16][4];
static long win_id; /* graphics window id */
#ifdef TC
static void *th; /* draw_thread handle */
#else
static unsigned long th;
#endif
/* screen corners */
static double scrx[4],scry[4];
static double aspect = 1;
static double xscale=2.8/400,yscale=2.8/400;
static GLsizei xsize,ysize; /* window size */
static int initz_flag = 0; /* z buffer */
static float projmat[16]; /* for saving projection matrix */
#define P_ORTHO 0
#define P_PERSP 1
static int projmode = P_ORTHO; /* kind of projection to do */
#define NO_STEREO 0
#define CROSS_STEREO 1
static int stereomode = NO_STEREO;
#define NOLIST 0
#define NORMALLIST 1
#define RESETLIST 2
static int dlistflag = NOLIST; /* whether to use display list */
static int facetshow_flag = 1; /* whether to show facets */
static GLfloat linewidth = 1.0;
static REAL edge_bias = 0.005; /* amount edges drawn in front */
static int arraysflag=0; /* whether to use OpenGL 1.1 arrays */
struct vercol { float c[4]; float n[3]; float x[3]; int inx; };
static struct vercol *fullarray;
static int amax; /* allocated size of final array */
static int edgestart,edgecount,facetstart,facetcount;
static int vertexcount;
static struct vercol *edgearray,*facetarray;
static int emax,fmax; /* allocated */
static long arrays_timestamp; /* for remembering surface version */
static int interleaved_flag = 1; /* whether to do arrays as interleaved */
static int indexing_flag = 1; /* whether to use indexed arrays (smaller,but random access) */
static int *indexarray;
static int strips_flag; /* whether to do GL strips */
static int strip_color_flag; /* whether to color facets according to strip number */
static void make_strips(void);
static void make_indexlists(void);
struct stripstruct { int mode; /* GL_TRIANGLE_STRIP or GL_LINE_STRIP */
int start; /* starting offset in indexarray */
int count; /* number of vertices in strip */
};
static struct stripstruct *striparray;
static int stripcount; /* size of striparray */
static int estripcount; /* number of edge strips */
static int fstripcount; /* number of facet strips */
static int *stripdata;
static int doing_lazy; /* whether oglgraph should do transforms itself */
static int q_flag; /* whether to print drawing stats */
static REAL gleps = 1e-5; /* tolerance for identifying vertices */
// Note: using indexed arrays seems not to have any particular benefits.
/********************************************************************
*
* function: enlarge_edge_array()
*
* purpose: Expand the space for the edge list
*/
void enlarge_edge_array(void)
{ int more = emax + 10;
edgearray = (struct vercol*)kb_realloc((char*)edgearray,
(emax+more)*sizeof(struct vercol));
emax += more;
}
/********************************************************************
*
* function: enlarge_facet_array()
*
* purpose: Expand the space for the facet list
*/
void enlarge_facet_array(void)
{ int more = web.skel[FACET].count + 10;
facetarray = (struct vercol*)kb_realloc((char*)facetarray,
(fmax+more)*sizeof(struct vercol));
fmax += more;
}
/***********************************************************************
*
* function: kb_glNormal3fv() etc.
*
* purpose: Either save current normal in kb_norm[] for later list entry,
* or pass it on to gl.
*/
static float kb_norm[3] = { 0.0, 0.0, 1.0 }; /* state of normal vector */
void kb_glNormal3fv(float *v) /* save for edges and facets */
{ if ( !arraysflag ) glNormal3fv(v);
else { kb_norm[0] = v[0]; kb_norm[1] = v[1]; kb_norm[2] = v[2]; }
}
void kb_glNormal3dv(REAL *v) /* save for edges and facets */
{ kb_norm[0] = (float)v[0]; kb_norm[1] = (float)v[1]; kb_norm[2] = (float)v[2];
if ( !arraysflag ) glNormal3fv(kb_norm);
}
void kb_glAntiNormal3dv(REAL *v) /* save for edges and facets */
{ kb_norm[0] = -(float)v[0]; kb_norm[1] = -(float)v[1]; kb_norm[2] = -(float)v[2];
if ( !arraysflag ) glNormal3fv(kb_norm);
}
/***********************************************************************
*
* function: e_glColor()
*
* purpose: Either save current edge color in er,eg,eb for later list entry,
* or pass it on to gl.
*/
static float er,eg,eb,ea; /* current edge color */
void e_glColor(int c)
{
if ( edge_rgb_color_attr > 0 )
{
if ( !arraysflag ) glColor4ubv((const GLubyte*)&c);
else
{ er=(float)(((c>>24)&0xFF)/255.); eg=(float)(((c>>16)&0xFF)/255.);
eb=(float)(((c>>8)&0xFF)/255.); ea= (float)(((c)&0xFF)/255.);
}
}
else
{ if ( !arraysflag ) glColor4fv(rgba[c]);
else
{ er = rgba[c][0]; eg = rgba[c][1]; eb = rgba[c][2]; ea = rgba[c][3]; }
}
}
/*********************************************************************
*
* function: e_glVertex3dv()
*
* purpose: Either save current edge data in edge list, or pass on to gl.
*/
void e_glVertex3dv(double *x)
{ if ( !arraysflag ) { glVertex3dv(x); return; }
if ( edgecount > emax-5 ) enlarge_edge_array();
edgearray[edgecount].c[0] = er;
edgearray[edgecount].c[1] = eg;
edgearray[edgecount].c[2] = eb;
edgearray[edgecount].c[3] = ea;
edgearray[edgecount].x[0] = (float)x[0];
edgearray[edgecount].x[1] = (float)x[1];
edgearray[edgecount].x[2] = (float)x[2];
edgearray[edgecount].n[0] = kb_norm[0];
edgearray[edgecount].n[1] = kb_norm[1];
edgearray[edgecount].n[2] = kb_norm[2];
edgecount++;
}
/***********************************************************************
*
* function: f_glColor()
*
* purpose: Either save current facet color in fr,fg,fb for later list entry,
* or pass it on to gl.
*/
static float fr,fg,fb,fa; /* current facet color */
void f_glColor(int c)
{
if ( facet_rgb_color_attr > 0 )
{
if ( !arraysflag ) glColor4ubv((const GLubyte*)&c);
else
{ fr=(float)(((c>>24)&0xFF)/255.); fg=(float)(((c>>16)&0xFF)/255.);
fb=(float)(((c>>8)&0xFF)/255.); fa=(float)(((c)&0xFF)/255.);
}
}
else
{ if ( !arraysflag ) glColor4fv(rgba[c]);
else
{ fr = rgba[c][0]; fg = rgba[c][1]; fb = rgba[c][2]; fa = rgba[c][3]; }
}
}
/*********************************************************************
*
* function: f_glVertex3dv()
*
* purpose: Either save current facet data in facet list, or pass on to gl.
*/
void f_glVertex3dv(double *x)
{ if ( !arraysflag ) { glVertex3dv(x); return; }
if ( facetcount > fmax-5 ) enlarge_facet_array();
facetarray[facetcount].c[0] = fr;
facetarray[facetcount].c[1] = fg;
facetarray[facetcount].c[2] = fb;
facetarray[facetcount].c[3] = fa;
facetarray[facetcount].x[0] = (float)x[0];
facetarray[facetcount].x[1] = (float)x[1];
facetarray[facetcount].x[2] = (float)x[2];
facetarray[facetcount].n[0] = kb_norm[0];
facetarray[facetcount].n[1] = kb_norm[1];
facetarray[facetcount].n[2] = kb_norm[2];
facetcount++;
}
/* gl matrices have vector on left! */
typedef double Matrix[4][4];
Matrix vt3 = /* gl transform matrix */
{ {0.,0.,1.,0.},
{1.,0.,0.,0.},
{0.,-1.,0.,0.},
{0.,0.,0.,1.} };
Matrix vt3p = /* gl transform matrix, perspective version */
{ {0.,0.,1.,0.},
{1.,0.,0.,0.},
{0.,1.,0.,0.},
{0.,0.,0.,1.} };
Matrix vt2 = /* gl transform matrix */
{ {2.,0.,0.,0.}, /* can't figure why I need the 2's */
{0.,-2.,0.,0.},
{0.,0.,2.,0.},
{0.,0.,0.,1.} };
Matrix flip = /* gl transform matrix */
{ {1.,0.,0.,0.},
{0.,1.,0.,0.},
{0.,0.,-1.,0.},
{0.,0.,0.,1.} };
Matrix flip2D = /* gl transform matrix */
{ {1.,0.,0.,0.},
{0.,-1.,0.,0.},
{0.,0.,1.,0.},
{0.,0.,0.,1.} };
static long prev_timestamp; /* for remembering surface version */
#define MM_ROTATE 1
#define MM_TRANSLATE 2
#define MM_SCALE 3
#define MM_SPIN 4
#define MM_SLICE 5
static int mouse_mode = MM_ROTATE;
static int newarraysflag = 0; /* to cause rebuild of arrays */
static int dindex = 1; /* display list object index */
void CALLBACK draw_screen ARGS((void));
void Ogl_init(void)
{
}
void Ogl_finish(void)
{
}
void graph_new_surface(void)
{ /* to account for global deallocation at start of new surface */
fullarray = NULL;
edgearray = NULL;
facetarray = NULL;
indexarray = NULL;
striparray = NULL;
stripdata = NULL;
}
void init_Oglz ARGS((void));
int oldx,oldy,newx,newy; /* for tracking motion */
int basex=0,basey=0; /* translation to do on object */
/************************************************************************
*
* function: pick_func()
*
* purpose: To handle mouse picking of element. Invoked by right click.
*/
#define PICKBUFLENGTH 500
GLuint pickbuf[PICKBUFLENGTH];
void CALLBACK pick_func(AUX_EVENTREC *rec)
{ GLint hits, viewport[4];
int i,n;
unsigned int enearz = 0xFFFFFFFF;
unsigned int fnearz = 0xFFFFFFFF;
facet_id f_id = NULLID;
edge_id e_id = NULLID;
vertex_id v_id = NULLID;
int count;
glSelectBuffer(PICKBUFLENGTH,pickbuf);
glGetIntegerv(GL_VIEWPORT,viewport);
glMatrixMode(GL_PROJECTION);
glPushMatrix();
glRenderMode(GL_SELECT); /* see what picked when drawn */
glLoadIdentity();
gluPickMatrix(rec->data[0],rec->data[1],4,4,viewport);
glMultMatrixf(projmat);
if ( SDIM >= 3 ) glMultMatrixd(flip[0]); /* don't know why, but need */
else glMultMatrixd(flip2D[0]);
if ( arraysflag ) /* no picking during arrays */
{ arraysflag = 0; graph_timestamp = ++global_timestamp;
draw_screen();
arraysflag = 1; graph_timestamp = ++global_timestamp;
} else
draw_screen();
hits = glRenderMode(GL_RENDER); /* back to ordinary drawing */
if ( hits < 0 )
{ hits = PICKBUFLENGTH/4; /* buffer overflow */
kb_error(2541,
"Pick buffer overflow; selected element may not be foreground element.\n",
WARNING);
}
for ( i=0, n=0 ; (i < hits) && (n < PICKBUFLENGTH-4) ; i++, n += count + 3 )
{
count = pickbuf[n];
switch ( id_type(pickbuf[n+3]) )
{ case FACET:
if ( pickbuf[n+1] < fnearz )
{ f_id = pickbuf[n+3]; fnearz = pickbuf[n+1]; }
break;
case EDGE:
if ( pickbuf[n+1] < enearz )
if ( (pickbuf[n+3] != NULLEDGE) || !valid_id(e_id) )
{ e_id = pickbuf[n+3]; enearz = pickbuf[n+1]; }
break;
}
}
printf("\n");
if ( valid_id(e_id) )
{ /* check for vertex in common to picked edges */
for ( i = 0, n = 0 ; (i < hits) && (n < PICKBUFLENGTH-4) ; i++, n += count+3 )
{ element_id id,ee_id;
int ii,nn,ccount;
count = pickbuf[n];
id = pickbuf[n+3];
if ( (id_type(id) == EDGE) && valid_id(id) )
{ vertex_id v1 = get_edge_headv(id);
vertex_id v2 = get_edge_tailv(id);
for ( ii = i+1, nn = n+count+3 ; (ii < hits) && (n < PICKBUFLENGTH-4) ; ii++, nn += ccount + 3 )
{ ccount = pickbuf[nn];
ee_id = pickbuf[nn+3];
if ( (id_type(ee_id) == EDGE) && valid_id(ee_id)
&& !equal_element(id,ee_id) )
{ if ( v1 == get_edge_tailv(ee_id) )
{ v_id = v1; break; }
if ( v1 == get_edge_headv(ee_id) )
{ v_id = v1; break; }
if ( v2 == get_edge_tailv(ee_id) )
{ v_id = v2; break; }
if ( v2 == get_edge_headv(ee_id) )
{ v_id = v2; break; }
}
}
}
}
if ( valid_id(v_id) )
{ pickvnum = loc_ordinal(v_id) + 1;
sprintf(msg,"Picked vertex %d\n",pickvnum);
outstring(msg);
}
pickenum = loc_ordinal(e_id) + 1;
sprintf(msg,"Picked edge %d\n",pickenum);
outstring(msg);
}
else if ( e_id == NULLEDGE )
outstring("Picked facet subdivision edge.\n");
if ( valid_id(f_id) )
{ pickfnum = loc_ordinal(f_id) + 1;
sprintf(msg,"Picked facet %d\n",pickfnum);
outstring(msg);
}
outstring(current_prompt);
glMatrixMode(GL_PROJECTION);
glPopMatrix();
} /* end pick_func */
/***********************************************************
*
* function: mouse_down_func()
*
* purpose: Called on left button down, records position.
*/
void CALLBACK mouse_down_func(AUX_EVENTREC *rec)
{ oldx = (short)rec->data[0]; oldy = (short)rec->data[1];
}
/***********************************************************
*
* function: mouse_up_func()
*
* purpose: Called on left button up, records position as base.
*/
void CALLBACK mouse_up_func(AUX_EVENTREC *rec)
{
basex = newx;
basey = newy;
}
/*******************************************************************
*
* function: mouse_loc_func()
*
* purpose: Called as mouse moves with left button down, this
* moves surface according to current mouse_mode.
*/
void CALLBACK mouse_loc_func(AUX_EVENTREC *rec)
{ int i,j;
newx = (short)rec->data[0];
newy =(short)rec->data[1];
switch ( mouse_mode )
{ case MM_ROTATE:
mat_mult(to_focus,view,view,HOMDIM,HOMDIM,HOMDIM);
fix_ctm(view,(double)( newx-oldx),-(double)(newy - oldy));
mat_mult(from_focus,view,view,HOMDIM,HOMDIM,HOMDIM);
break;
case MM_SCALE:
mat_mult(to_focus,view,view,HOMDIM,HOMDIM,HOMDIM);
for(i = 0 ; i < HOMDIM-1; i++ )
for ( j = 0 ; j < HOMDIM ; j++ )
view[i][j] *= 1.0 +0.002*(newx-oldx);
mat_mult(from_focus,view,view,HOMDIM,HOMDIM,HOMDIM);
break;
case MM_SCALE: /* slicing altitude */
slice_coeff[SDIM] += (newx-oldx)*xscale;
break;
case MM_TRANSLATE:
if ( SDIM == 2 )
{ view[0][2] += (newx-oldx)*xscale;
view[1][2] -= (newy-oldy)*yscale;
to_focus[0][2] -= (newx-oldx)*xscale;
to_focus[1][2] += (newy-oldy)*yscale;
from_focus[0][2] += (newx-oldx)*xscale;
from_focus[1][2] -= (newy-oldy)*yscale;
} else
{
view[1][HOMDIM-1] += (newx-oldx)*xscale;
view[2][HOMDIM-1] -= (newy-oldy)*yscale;
to_focus[1][HOMDIM-1] -= (newx-oldx)*xscale;
to_focus[2][HOMDIM-1] += (newy-oldy)*yscale;
from_focus[1][HOMDIM-1] += (newx-oldx)*xscale;
from_focus[2][HOMDIM-1] -= (newy-oldy)*yscale;
};
break;
case MM_SPIN: /* about z axis */
{ MAT2D(rot,MAXCOORD+1,MAXCOORD+1);
REAL dth;
REAL dang; /* fourth dimension */
for ( i = 0 ; i < HOMDIM ; i++ )
{ for ( j = 0 ; j < HOMDIM ; j++ )
rot[i][j] = 0.0;
rot[i][i] = 1.0;
}
dth = (newx - oldx)/300.0*M_PI;
dang = (newy - oldy)/300.0*M_PI;
if ( SDIM == 2 )
{ rot[0][0] = rot[1][1] = cos(dth);
rot[0][1] = -(rot[1][0] = sin(dth));
} else
{ rot[1][1] = rot[2][2] = cos(dth);
rot[1][2] = -(rot[2][1] = sin(dth));
}
mat_mult(to_focus,view,view,HOMDIM,HOMDIM,HOMDIM);
mat_mult(rot,view,view,HOMDIM,HOMDIM,HOMDIM);
mat_mult(from_focus,view,view,HOMDIM,HOMDIM,HOMDIM);
}
break;
}
oldx = newx; oldy = newy;
}
/************************************************************************
*
* function: reshape_func()
*
* purpose: handle window resize messages.
*/
void CALLBACK reshape_func ( GLsizei x, GLsizei y )
{ xsize = x; ysize = y;
aspect = (double)y/x;
glViewport(0,0,x,y);
if ( aspect > 1 ) { xscale = 2.8/aspect/x; yscale = 2.8/y; }
else { xscale = 2.8/x; yscale = 2.8*aspect/y; }
if ( x < y )
{ minclipx = -1.5; maxclipx = 1.5;
minclipy = -1.5*y/x; maxclipy = 1.5*y/x;
}
else
{ minclipx = -1.5*x/y; maxclipx = 1.5*x/y;
minclipy = -1.5; maxclipy = 1.5;
}
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
if ( (projmode == P_PERSP) || stereomode )
{
gluPerspective((float)(y/1600.*180/3.14159),1/aspect,1.0,20.0);
if ( SDIM == 2 ) glMultMatrixd(vt2[0]);
else glMultMatrixd(vt3p[0]); /* rotate axes */
}
else
{
if ( aspect <= 1.0 )
{ glOrtho(scrx[0],scrx[2],aspect*scry[0],aspect*scry[2],-20.0,20.0);
minclipx = scrx[0]; maxclipx = scrx[2];
minclipy = aspect*scry[2]; maxclipy = aspect*scry[0];
}
else
{ glOrtho(scrx[0]/aspect,scrx[2]/aspect,scry[0],scry[2],-20.0,20.0);
minclipx = scrx[0]/aspect; maxclipx = scrx[2]/aspect;
minclipy = scry[2]; maxclipy = scry[0];
}
if ( SDIM == 2 ) glMultMatrixd(vt2[0]); /* upside down */
else glMultMatrixd(vt3[0]); /* upside down and rotate axes */
}
glGetFloatv(GL_PROJECTION_MATRIX,projmat); // save
}
/***********************************************************************
*
* Functions: key callbacks
*
* purpose: handle keystrokes in graphics window.
*/
void CALLBACK up_arrow (void) { view_transform("\036"); }
void CALLBACK down_arrow (void) { view_transform("\037"); }
void CALLBACK left_arrow (void) { view_transform("\035"); }
void CALLBACK right_arrow (void) { view_transform("\034"); }
void CALLBACK r_key (void) { mouse_mode = MM_ROTATE; }
void CALLBACK t_key (void) { mouse_mode = MM_TRANSLATE; }
void CALLBACK z_key (void) { mouse_mode = MM_SCALE; }
void CALLBACK c_key (void) { mouse_mode = MM_SPIN;}
void CALLBACK l_key (void) { if ( slice_view ) mouse_mode = MM_SLICE;}
void CALLBACK b_key (void)
{ edge_bias -= 0.001;
sprintf(msg,"\nEdge front bias now %f\n",edge_bias); outstring(msg);
outstring(current_prompt);
}
void CALLBACK B_key (void)
{ edge_bias += 0.001;
sprintf(msg,"\nEdge front bias now %f\n",edge_bias); outstring(msg);
outstring(current_prompt);
}
void CALLBACK R_key (void)
{
resize();
}
void CALLBACK minus_key (void)
{ if ( linewidth > 0.6 ) { linewidth -= 0.5; glLineWidth(linewidth);} }
void CALLBACK plus_key (void)
{ if ( linewidth < 9.9 ) { linewidth += 0.5; glLineWidth(linewidth);}}
void CALLBACK e_key (void)
{ edgeshow_flag = !edgeshow_flag; graph_timestamp = ++global_timestamp;
newarraysflag = 1;}
void CALLBACK f_key (void)
{ facetshow_flag = !facetshow_flag; graph_timestamp = ++global_timestamp;
newarraysflag = 1;}
void CALLBACK g_key (void)
{ normflag = !normflag; graph_timestamp = ++global_timestamp;
newarraysflag = 1;}
void CALLBACK m_key (void) { view_transform("m"); }
void CALLBACK i_key (void) { interleaved_flag = !interleaved_flag;
outstring(interleaved_flag ? "Interleaving ON.\n":"Interleaving OFF.\n");
outstring(current_prompt);
newarraysflag = 1;
}
void CALLBACK I_key (void) { indexing_flag = !indexing_flag;
outstring(indexing_flag ? "Array indexing ON.\n":"Array indexing OFF.\n");
outstring(current_prompt);
newarraysflag = 1;
}
void CALLBACK S_key (void) { strips_flag = !strips_flag;
outstring(strips_flag ? "Element strips ON.\n":"Element strips OFF.\n");
outstring(current_prompt);
normflag = 1; /* gourard shading */
indexing_flag = 1;
newarraysflag = 1;
}
void CALLBACK Y_key (void) /* color strips */
{ int *fcolors;
int i;
fcolors = (int*)temp_calloc(web.skel[FACET].maxcount,sizeof(int));
for ( i = 0 ; i < web.skel[FACET].maxcount ; i++ )
fcolors[i] = get_facet_color(i);
if ( !strips_flag ) S_key(); /* make sure strips on */
strip_color_flag = 1;
newarraysflag = 1;
draw_screen(); /* get facets colored */
newarraysflag = 1;
draw_screen(); /* draw colored facets */
strip_color_flag = 0;
for ( i = 0 ; i < web.skel[FACET].maxcount ; i++ )
set_facet_color(i,fcolors[i]);
temp_free((char*)fcolors);
}
void CALLBACK F_key (void)
{
if ( pickvnum > 0 )
{ int i,m;
REAL *x,xx[MAXCOORD];
REAL focus[MAXCOORD];
focus_vertex_id = get_ordinal_id(VERTEX,pickvnum-1);
x = get_coord(focus_vertex_id);
for ( m = 0 ; m < SDIM ; m++ ) xx[m] = x[m];
if ( torus_display_mode == TORUS_CLIPPED_MODE )
{
for ( m = 0 ; m < SDIM ; m++ )
{ int wrap = (int)floor(SDIM_dot(web.inverse_periods[m],x));
for ( i = 0 ; i < SDIM ; i++ )
xx[i] -= wrap*web.torus_period[m][i];
}
}
matvec_mul(view,xx,focus,HOMDIM-1,HOMDIM-1);
for ( i = 0 ; i < SDIM ; i++ )
{ to_focus[i][HOMDIM-1] = -focus[i] - view[i][HOMDIM-1];
from_focus[i][HOMDIM-1] = focus[i] + view[i][HOMDIM-1];
}
}
}
void CALLBACK D_key (void)
{ dlistflag = dlistflag ? NOLIST:RESETLIST;
if ( dlistflag ) outstring("\nOpenGL display list now ON.\n");
else outstring("\nOpenGL display list now OFF.\n");
outstring(current_prompt);
graph_timestamp = ++global_timestamp; /* force recalculate arrays */
}
void CALLBACK a_key (void)
{ if ( strcmp(opengl_version,"1.1") < 0 )
{ sprintf(errmsg,"Vertex arrays require OpenGL version at least 1.1. This is %s.\n",
opengl_version);
kb_error(2542,errmsg,WARNING);
return;
}
arraysflag = !arraysflag;
if ( arraysflag )
{ /* Workaround really bizarre line-drawing bug */
if ( linewidth == 1.0 ) { linewidth = 0.5; glLineWidth(0.5); }
outstring("\nOpenGL vertex arrays now ON.\n");
glInterleavedArrays(GL_C4F_N3F_V3F,0,(void*)fullarray);
newarraysflag = 1;
}
else
{
glDisableClientState(GL_COLOR_ARRAY);
glDisableClientState(GL_NORMAL_ARRAY);
glDisableClientState(GL_VERTEX_ARRAY);
outstring("\nOpenGL vertex_arrays now OFF.\n");
}
outstring(current_prompt);
}
void CALLBACK s_key (void)
{ stereomode = (stereomode==NO_STEREO) ? CROSS_STEREO:NO_STEREO;
if (stereomode)
{ if ( dlistflag == NOLIST ) dlistflag = RESETLIST;}
else if ( arraysflag ) dlistflag = NOLIST;
reshape_func(xsize,ysize);
}
void CALLBACK p_key (void)
{ if ( stereomode )
outstring("\nOpenGL projection now CROSS-EYED STEREO.\n");
else if ( projmode==P_ORTHO )
{ projmode=P_PERSP; outstring("\nOpenGL projection now PERSPECTIVE.\n");}
else
{ projmode=P_ORTHO; outstring("\nOpenGL projection now ORTHOGONAL.\n");}
outstring(current_prompt);
reshape_func(xsize,ysize);
}
void CALLBACK Q_key (void)
{ q_flag = !q_flag;
outstring(q_flag ? "\nPrinting drawing stats ON\n":"\nPrinting drawing stats OFF\n");
outstring(current_prompt);
}
void CALLBACK help_key (void)
{ outstring("\nGraphics window help:\n");
outstring("Left mouse: move Right mouse: pick\n");
outstring("Graphics window keys:\n");
outstring(mouse_mode==MM_ROTATE?"r Rotate mode for left mouse button, now ACTIVE\n":
"r Rotate mode for left mouse button\n");
outstring(mouse_mode==MM_TRANSLATE?"t Translate mode for left mouse button, now ACTIVE\n":
"t Translate mode for left mouse button\n");
outstring(mouse_mode==MM_SCALE?"z Zoom mode for left mouse button, now ACTIVE\n":
"z Zoom mode for left mouse button\n");
outstring(mouse_mode==MM_SPIN?"c Clockwise/counterclockwise mode, now ACTIVE\n":
"c Clockwise/counterclockwise mode\n");
outstring("W Widen edges\n");
outstring("w Narrow edges\n");
outstring("B Increase edge front bias by 0.001\n");
outstring("b Decrease edge front bias by 0.001\n");
outstring(normflag? "g Gourard shading (smooth shading) toggle, now ON\n":
"g Gourard shading (smooth shading) toggle, now OFF\n" );
outstring("R Reset view\n");
outstring("m Center image\n");
outstring(edgeshow_flag?"e Toggle showing all edges, now ON\n":
"e Toggle showing all edges, now OFF\n");
outstring(facetshow_flag?"f Toggle showing facets, now ON\n":
"f Toggle showing facets, now OFF\n");
outstring(projmode==P_PERSP?"p Toggle orthogonal/perspective projection, now perspective\n":
"p Toggle orthogonal/perspective projection, now orthogonal\n");
outstring("s Toggle cross-eyed stereo\n");
outstring("F Set rotate/zoom focus to last picked vertex\n");
outstring("arrow keys translate image\n");
outstring("H Guru-level help items\n");
outstring(current_prompt);
}
void CALLBACK H_key(void) /* guru level help */
{
outstring("\nFollowing for fiddling with OpenGL drawing modes:\n");
outstring(normflag? "g Gourard shading (smooth shading) toggle, now ON\n":
"g Gourard shading (smooth shading) toggle, now OFF\n" );
outstring(dlistflag?"D Toggle using display list, now ON\n":
"D Toggle using display list, now OFF\n");
outstring(arraysflag?"a Toggle using vertex and color arrays, now ON\n"
:"a Toggle using vertex and color arrays, now OFF\n");
outstring(indexing_flag ? "I Indexed vertex arrays, now ON\n"
: "I Indexed vertex arrays, now OFF\n");
outstring(interleaved_flag ? "i Interleaved vertex arrays, now ON\n"
: "i Interleaved vertex arrays, now OFF\n");
outstring(strips_flag?
"S Use element strips, now ON (indexed elements automatically turned on)\n"
:"S Use element strips, now OFF\n");
outstring("Y One-time coloring of strips generated in S mode.\n");
outstring(" Caution: assumes display facets same as real, with no gaps.\n");
outstring("Q Toggle printing some statistics during drawing\n");
outstring(current_prompt);
}
/* lighting info for surface */
static GLfloat mat_specular[] = {.5f,.5f,.5f,1.0f};
static GLfloat mat_shininess[] = {10.0f};
static GLfloat mat_diffuse[] = {1.0f,1.0f,1.0f,1.0f};
static GLfloat mat_white[] = {1.0f,1.0f,1.0f,1.0f};
static GLfloat mat_emission[] = {0.3f,0.3f,0.3f,1.0f};
#define INTENSITY1 0.5f
static GLfloat light0_position[] = {1.0f,0.0f,1.0f,0.0f}; // front
static GLfloat light0_diffuse[] = {INTENSITY1,INTENSITY1,INTENSITY1,1.0f};
static GLfloat light0_ambient[] = {.3f,.3f,.3f,1.0f};
#define INTENSITY2 0.5f
static GLfloat light1_position[] = {0.0f,0.0f,1.0f,0.0f}; // above
static GLfloat light1_diffuse[] = {INTENSITY2,INTENSITY2,INTENSITY2,1.0f};
static GLfloat light_none[] = {0.f,0.f,0.f,.0f};
/*****************************************************************
*
* function: draw_thread()
*
* purpose: Create OpenGL display thread and window.
*/
//unsigned long __stdcall draw_thread(void *arglist)
void __cdecl draw_thread(void *arglist)
{ int i,j;
draw_thread_id = GetCurrentThreadId();
for ( i = 0 ; i < 16 ; i++ )
for ( j = 0 ; j < 4 ; j++ )
rgba[i][j] = (float)rgb_colors[i][j];
background_color = LIGHTBLUE;
auxInitPosition(0,0,400,400);
auxInitDisplayMode(AUX_DOUBLE | AUX_RGBA | AUX_DEPTH);
auxInitWindow(datafilename);
auxMouseFunc(AUX_LEFTBUTTON,AUX_MOUSEUP,mouse_up_func);
auxMouseFunc(AUX_LEFTBUTTON,AUX_MOUSELOC,mouse_loc_func);
auxMouseFunc(AUX_LEFTBUTTON,AUX_MOUSEDOWN,mouse_down_func);
auxMouseFunc(AUX_RIGHTBUTTON,AUX_MOUSEDOWN,pick_func);
auxKeyFunc(AUX_UP,up_arrow);
auxKeyFunc(AUX_LEFT,left_arrow);
auxKeyFunc(AUX_RIGHT,right_arrow);
auxKeyFunc(AUX_DOWN,down_arrow);
auxKeyFunc(AUX_t,t_key);
auxKeyFunc(AUX_z,z_key);
auxKeyFunc(AUX_r,r_key);
auxKeyFunc(AUX_l,l_key);
auxKeyFunc(AUX_R,R_key);
auxKeyFunc(AUX_D,D_key);
auxKeyFunc(AUX_p,p_key);
auxKeyFunc(AUX_s,s_key);
auxKeyFunc(AUX_S,S_key);
auxKeyFunc(AUX_Y,Y_key);
auxKeyFunc(AUX_e,e_key);
auxKeyFunc(AUX_f,f_key);
auxKeyFunc(AUX_g,g_key);
auxKeyFunc(AUX_F,F_key);
auxKeyFunc(AUX_c,c_key);
auxKeyFunc(AUX_B,B_key);
auxKeyFunc(AUX_b,b_key);
auxKeyFunc(AUX_W,plus_key);
auxKeyFunc(AUX_w,minus_key);
auxKeyFunc(AUX_h,help_key);
auxKeyFunc(AUX_H,H_key);
auxKeyFunc(AUX_a,a_key);
auxKeyFunc(AUX_m,m_key);
auxKeyFunc(AUX_i,i_key);
auxKeyFunc(AUX_I,I_key);
auxKeyFunc(AUX_Q,Q_key);
auxReshapeFunc(reshape_func);
hwnd = auxGetHWND();
ShowWindow(hwnd,SW_SHOW);
SetWindowPos(hwnd,HWND_NOTOPMOST ,0,0,0,0,
SWP_NOSIZE | SWP_NOMOVE);
SetForegroundWindow(hwnd);
glDepthFunc(GL_LEQUAL);
glEnable(GL_DEPTH_TEST);
glEnable(GL_NORMALIZE);
glEnable(GL_COLOR_MATERIAL);
glColorMaterial(GL_FRONT_AND_BACK,GL_AMBIENT_AND_DIFFUSE);
//glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, mat_specular);
//glMaterialfv(GL_FRONT_AND_BACK, GL_SHININESS, mat_shininess);
glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, mat_white);
//glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, mat_emission);
glEnable(GL_LIGHTING);
glLightfv(GL_LIGHT0, GL_POSITION, light0_position);
glLightfv(GL_LIGHT0, GL_DIFFUSE, light0_diffuse);
glLightfv(GL_LIGHT0, GL_AMBIENT, light0_ambient);
glLightfv(GL_LIGHT1, GL_POSITION, light1_position);
glLightfv(GL_LIGHT1, GL_DIFFUSE, light1_diffuse);
glLightfv(GL_LIGHT0, GL_SPECULAR, light_none);
glLightModeli(GL_LIGHT_MODEL_TWO_SIDE,GL_TRUE);
/* screen corners */
scrx[0] = scrx[1] = -1.4;
scrx[2] = scrx[3] = 1.4;
scry[0] = scry[3] = 1.4;
scry[1] = scry[2] = -1.4;
go_display_flag = 1; /* default, since fast graphics */
/* version check */
strncpy(opengl_version,glGetString(GL_VERSION),sizeof(opengl_version));
if ( strcmp(opengl_version,"1.1") >= 0 ) arraysflag = 1;
auxMainLoop(draw_screen);
//return 0;
}
/************************************************************************
*
* function: init_Oglz()
*
* purpose: start up graphics thread
*/
#include
void init_Oglz(void)
{ int n;
if ( !initz_flag )
{ initz_flag = 1;
if ( !to_focus )
{ to_focus = dmatrix(0,MAXCOORD,0,MAXCOORD);
from_focus = dmatrix(0,MAXCOORD,0,MAXCOORD);
for ( n = 0 ; n <= MAXCOORD ; n++ )
to_focus[n][n] = from_focus[n][n] = 1.0;
}
//th = CreateThread(NULL,0,draw_thread,0,0,&draw_thread_id);
th=_beginthread(draw_thread,0,0);
}
}
/****************************************************************
*
* function: Oglz_start()
*
* purpose: To be called at the start of each Evolver-initiated redraw.
*/
void Oglz_start(void)
{
if ( initz_flag == 0 ) init_Oglz();
SetWindowText(hwnd,datafilename);
if ( !to_focus )
{ int n;
to_focus = dmatrix(0,MAXCOORD,0,MAXCOORD);
from_focus = dmatrix(0,MAXCOORD,0,MAXCOORD);
for ( n = 0 ; n <= MAXCOORD ; n++ )
to_focus[n][n] = from_focus[n][n] = 1.0;
}
}
/******************************************************************
*
* function: Oglz_edge()
*
* purpose: graph one edge.
*/
void Oglz_edge(
struct graphdata *g,
edge_id e_id)
{
int k;
int e_color;
e_color = g[0].ecolor;
if ( e_color == CLEAR ) return;
if ( (e_color < 0) || (e_color >= IRIS_COLOR_MAX) )
e_color = DEFAULT_EDGE_COLOR;
glLoadName(e_id); // for picking
/* display */
e_glColor(e_color);
glBegin(GL_LINES);
for ( k = 0 ; k < 2 ; k++ )
e_glVertex3dv(g[k].x);
glEnd();
}
/******************************************************************
*
* function: Oglz_facet()
*
* purpose: graph one facet.
*/
static float norm[3];
void Oglz_facet(
struct graphdata *g,
facet_id f_id)
{
int i,k;
REAL len;
facetedge_id fe = NULLID;
/* need normal for lighting */
for ( i = 0 ; i < 3 ; i++ )
{ int ii = (i+1)%3;
int iii = (i+2)%3;
norm[i] = (float)((g[1].x[ii]-g[0].x[ii])*(g[2].x[iii]-g[0].x[iii])
- (g[1].x[iii]-g[0].x[iii])*(g[2].x[ii]-g[0].x[ii]));
}
len = sqrt(dotf(norm,norm,3));
if ( len <= 0.0 ) return;
for ( i = 0 ; i < 3 ; i++ ) norm[i]= (float)(norm[i]/len);
if ( web.hide_flag && (g[0].color != UNSHOWN)
&& facetshow_flag )
{ glLoadName(f_id); // for picking
if ( g[0].color != CLEAR )
{ if ( color_flag ) f_glColor(g->color);
else f_glColor(INDEX_TO_RGBA(WHITE));
kb_glNormal3fv(norm);
glBegin(GL_TRIANGLES);
for ( k = 0 ; k < 3 ; k++ )
{ if ( normflag ) kb_glNormal3dv(g[k].norm);
f_glVertex3dv(g[k].x);
}
glEnd();
}
if ( (g->color != g->backcolor) && (g->backcolor != CLEAR) )
{ REAL x[MAXCOORD];
f_glColor(g->backcolor);
for ( i = 0 ; i < 3 ; i++ ) norm[i] = -norm[i];
kb_glNormal3fv(norm);
glBegin(GL_TRIANGLES);
for ( k = 2 ; k >= 0 ; k-- )
{ for ( i = 0 ; i < 3 ; i++ )
x[i] = g[k].x[i] + thickness*norm[i];
if ( normflag ) kb_glAntiNormal3dv(g[k].norm);
f_glVertex3dv(x);
}
glEnd();
}
}
fe = valid_id(f_id) ? get_facet_fe(f_id) : NULLID;
for ( k = 0 ; k < 3 ; k++, fe = valid_id(fe)?get_next_edge(fe):NULLID )
{
if ( g[k].ecolor == CLEAR ) continue;
if ( !edgeshow_flag || (g[0].color == UNSHOWN) )
{ if ( (g[k].etype&EBITS) == INVISIBLE_EDGE ) continue;
}
glLoadName(g[k].id); /* for picking */
e_glColor(g[k].ecolor);
kb_glNormal3fv(norm);
glBegin(GL_LINES);
if ( normflag ) kb_glNormal3dv(g[k].norm);
e_glVertex3dv(g[k].x);
if ( normflag ) kb_glNormal3dv(g[(k+1)%3].norm);
e_glVertex3dv(g[(k+1)%3].x);
glEnd();
}
}
/**********************************************************************
*
* function: Oglz_end()
*
* purpose: to be called at end of presenting data.
*/
void Oglz_end(void)
{
prev_timestamp = graph_timestamp;
}
void Ogl_close(void)
{ //close_flag = 1;
//InvalidateRect(hwnd,NULL,FALSE);
kb_error(2175,"Sorry, OpenGL version can't restart show after close, so won't close.\n",
WARNING);
graph_timestamp = ++global_timestamp;
draw_screen();
}
void really_close(void)
{
auxCloseWindow();
glDeleteLists(dindex,1);
init_flag = 0;
initz_flag = 0;
win_id = -1;
go_display_flag = 0;
ExitThread(0);
}
/**********************************************************************
*
* function: vercolcomp()
*
* purpose: comparison function for sorting vertex data in case of indexed arrays.
*
*/
int vercolcomp(struct vercol *a, struct vercol *b)
{
int i;
for ( i = 0 ; i < 10 ; i++ )
{ REAL diff = ((float*)a)[i] - ((float*)b)[i];
if ( diff < -gleps ) return -1;
if ( diff > gleps ) return 1;
}
return 0;
}
/***********************************************************************
*
* function: eecomp()
*
* purpose: comparison function for sorting indexed edges
*/
int eecomp(const int *a, const int *b)
{ if ( *a < *b ) return -1;
if ( *a > *b ) return 1;
if ( a[1] > b[1] ) return 1;
if ( a[1] < b[1] ) return -1;
return 0;
}
/**********************************************************************
*
* function: draw_screen()
*
* purpose: Handle redraw messages from operating system.
*/
void CALLBACK draw_screen(void)
{ static int olddim = 0;
Matrix viewf;
int i,j;
ENTER_GRAPH_MUTEX
// Set up longjmp to return here in case of error
if ( setjmp(graphjumpbuf) )
{ return; }
//if ( close_flag ) really_close(); can't restart
/* build arrays if needed */
if ( arraysflag && (
((graph_timestamp != arrays_timestamp) && go_display_flag )
|| newarraysflag || (dlistflag == RESETLIST)) )
{ int oldflag;
if ( fullarray )
{ myfree((char*)fullarray);
fullarray = NULL;
}
edgecount = 0;
emax = (web.representation==SIMPLEX) ? SDIM*web.skel[FACET].count + 100 :
2*web.skel[EDGE].count+10; // 2 vertices per edge
edgearray = (struct vercol *)mycalloc(emax,sizeof(struct vercol));
facetcount = 0; fmax = 3*web.skel[FACET].count+10; // 3 vertices per facet
facetarray = (struct vercol *)mycalloc(fmax,sizeof(struct vercol));
if ( !edgearray || !facetarray )
{ erroutstring("Cannot allocate memory for graphics.\n");
goto bailout;
}
graph_start = Oglz_start;
graph_facet = Oglz_facet;
graph_edge = Oglz_edge;
graph_end = Oglz_end;
init_graphics = Ogl_init;
finish_graphics = Ogl_finish;
close_graphics = Ogl_close;
//glDisableClientState(GL_COLOR_ARRAY);
//glDisableClientState(GL_NORMAL_ARRAY);
//glDisableClientState(GL_VERTEX_ARRAY);
oldflag = markedgedrawflag;
markedgedrawflag = 1;
if ( !transform_colors_flag )
lazy_transforms_flag = 1; /* for graphgen use */
doing_lazy = lazy_transforms_flag; /* for use by oglgraph.c */
arrays_timestamp = graph_timestamp; /* here to prevent stale data */
graphgen(); /* fill in arrays */
lazy_transforms_flag = 0;
markedgedrawflag = oldflag;
if ( q_flag )
{ sprintf(msg,"\n%d edges, %d facets\n",edgecount/2,facetcount/3);
outstring(msg);
}
/* doing this here since facet_alpha_flag set in graphgen */
if ( facet_alpha_flag ) glEnable(GL_BLEND);
else glDisable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
/* unify lists */
fullarray = (struct vercol *)kb_realloc((char*)edgearray,
(edgecount+facetcount)*sizeof(struct vercol));
memcpy((char*)(fullarray+edgecount),(char*)facetarray,facetcount*sizeof(struct vercol));
myfree((char*)facetarray); facetarray = NULL; edgearray = NULL;
edgestart = 0; facetstart = edgecount;
/* Workaround really bizarre line-drawing bug */
if ( linewidth == 1.0 ) { linewidth = (float)1.1; glLineWidth(linewidth); }
if ( indexing_flag )
{
make_indexlists();
if ( q_flag )
{ sprintf(msg,"After indexing: %d unique vertices, %d unique edges\n",
vertexcount,edgecount/2);
outstring(msg);
}
if ( strips_flag ) make_strips();
}
/* declare arrays to OpenGL */
if ( interleaved_flag )
glInterleavedArrays(GL_C4F_N3F_V3F,sizeof(struct vercol),(void*)fullarray);
else // kludge for broken nVidia Detonater 2.08 driver
{ static float *colorarray;
if ( colorarray ) myfree((char*)colorarray);
colorarray = (float*)mycalloc(edgecount+facetcount,4*sizeof(float));
for ( i = 0 ; i < edgecount+facetcount ; i++ )
for ( j = 0 ; j < 4 ; j++ )
colorarray[4*i+j] = fullarray[i].c[j];
glColorPointer(4,GL_FLOAT,0,colorarray);
glNormalPointer(GL_FLOAT,sizeof(struct vercol),fullarray->n);
glVertexPointer(3,GL_FLOAT,sizeof(struct vercol),fullarray->x);
}
newarraysflag = 0;
if ( dlistflag )
{
glNewList(dindex,GL_COMPILE);
if ( indexing_flag )
{
glDrawElements(GL_TRIANGLES,facetcount,GL_UNSIGNED_INT,indexarray+facetstart);
glMatrixMode(GL_PROJECTION);
glTranslated(edge_bias,0.0,0.0); /* edges in front */
glDrawElements(GL_LINES,edgecount,GL_UNSIGNED_INT,indexarray+edgestart);
glTranslated(-edge_bias,0.0,0.0);
glMatrixMode(GL_MODELVIEW);
}
else
{
glDrawArrays(GL_TRIANGLES,facetstart,facetcount);
glMatrixMode(GL_PROJECTION);
glTranslated(edge_bias,0.0,0.0); /* edges in front */
glDrawArrays(GL_LINES,edgestart,edgecount);
glTranslated(-edge_bias,0.0,0.0);
glMatrixMode(GL_MODELVIEW);
}
glEndList();
dlistflag = NORMALLIST;
}
if ( q_flag ) outstring(current_prompt);
}
else
if ( (dlistflag != NORMALLIST) ||
((graph_timestamp != prev_timestamp) && go_display_flag ) )
{ /* regenerate display list */
graph_start = Oglz_start;
graph_facet = Oglz_facet;
graph_edge = Oglz_edge;
graph_end = Oglz_end;
init_graphics = Ogl_init;
finish_graphics = Ogl_finish;
close_graphics = Ogl_close;
if ( dlistflag != NOLIST )
{ glNewList(dindex,GL_COMPILE);
graphgen();
glEndList();
dlistflag = NORMALLIST;
}
}
if ( SDIM != olddim )
{ reshape_func(xsize,ysize); /* in case dimension changes */
olddim = SDIM;
}
glEnable(GL_LIGHT0);
//glEnable(GL_LIGHT1);
/* clear screen and zbuffer */
glClearColor(rgba[background_color][0],
rgba[background_color][1],
rgba[background_color][2],
rgba[background_color][3]
);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
if ( backcull_flag ) { glEnable(GL_CULL_FACE); }
else { glDisable(GL_CULL_FACE); }
glDepthFunc(GL_LEQUAL); /* so later things get drawn */
glMatrixMode(GL_MODELVIEW);
for ( i = 0 ; i < 4 ; i++ )
for ( j = 0 ; j < 4 ; j++ )
viewf[i][j] = view[(j<3)?j:(SDIM)][(i<3)?i:(SDIM)];
if ( SDIM == 2 )
{ for ( i = 0 ; i < 3 ; i++ ) viewf[i][2] = viewf[2][i] = 0.0;
viewf[2][2] = 1.0;
}
/* transpose, picking first 3 coordinates */
if ( (projmode == P_PERSP) || stereomode )
if ( SDIM == 2 ) viewf[3][2] -= 16;
else viewf[3][0] -= 16.0;
glLoadMatrixd(viewf[0]);
// for picking
if ( !arraysflag ) { glInitNames(); glPushName(0);}
// Now the actual drawing
if ( dlistflag )
{ if ( stereomode )
{ int w = (SDIM==2) ? 0 : 1;
// Stereo mode always perspective
viewf[3][w] -= 1.5; glLoadMatrixd(viewf[0]); glCallList(dindex);
viewf[3][w] += 3.0; glLoadMatrixd(viewf[0]); glCallList(dindex);
}
else glCallList(dindex);
}
else if ( arraysflag )
{ int i,j,m;
for ( m = 0 ; (m < transform_count) || (m < 1) ; m++ )
{ float tmat[4][4]; /* transform matrix in proper form */
if ( transforms_flag && doing_lazy && view_transform_det
&& (view_transform_det[m] == -1.0) )
{ /* have to flip normals */
for ( i = 0 ; i < edgecount+facetcount ; i++ )
for ( j = 0 ; j < 3 ; j++ )
fullarray[i].n[j] *= -1.0;
}
if ( transforms_flag && doing_lazy && view_transforms )
{ int hi = (SDIM <= 3) ? SDIM : 3;
for ( i = 0 ; i < hi; i++ )
{ for ( j = 0 ; j < hi; j++ )
tmat[i][j] = (float)view_transforms[m][j][i];
for ( ; j < 3 ; j++ ) tmat[i][j] = 0.0;
tmat[i][3] = (float)view_transforms[m][i][SDIM];
}
for ( ; i < 3 ; i++ )
{ for ( j = 0 ; j < 4 ; j++ ) tmat[i][j] = 0.0;
tmat[i][i] = 1.0;
}
for ( j = 0 ; j < hi ; j++ )
tmat[3][j] = (float)view_transforms[m][SDIM][j];
for ( ; j < 3 ; j++ )
tmat[3][j] = 0.0;
tmat[3][3] = (float)view_transforms[m][SDIM][SDIM];
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glMultMatrixf((float*)tmat);
}
if ( strips_flag )
{ int i;
/* do facets first, then edges in front */
for ( i = estripcount ; i < stripcount ; i++ )
glDrawElements(striparray[i].mode,striparray[i].count,GL_UNSIGNED_INT,stripdata+striparray[i].start);
glMatrixMode(GL_PROJECTION);
glTranslated(edge_bias,0.0,0.0);
for ( i = 0 ; i < estripcount ; i++ )
glDrawElements(striparray[i].mode,striparray[i].count,GL_UNSIGNED_INT,stripdata+striparray[i].start);
glTranslated(-edge_bias,0.0,0.0);
}
else if ( indexing_flag )
{
glDrawElements(GL_TRIANGLES,facetcount,GL_UNSIGNED_INT,indexarray+facetstart);
glMatrixMode(GL_PROJECTION);
glTranslated(edge_bias,0.0,0.0);
glDrawElements(GL_LINES,edgecount,GL_UNSIGNED_INT,indexarray+edgestart);
glTranslated(-edge_bias,0.0,0.0);
}
else
{
glDrawArrays(GL_TRIANGLES,facetstart,facetcount);
glMatrixMode(GL_PROJECTION);
glTranslated(edge_bias,0.0,0.0);
glDrawArrays(GL_LINES,edgestart,edgecount);
glTranslated(-edge_bias,0.0,0.0);
}
if ( transforms_flag && doing_lazy )
{ glMatrixMode(GL_MODELVIEW); glPopMatrix(); }
if ( transforms_flag && doing_lazy && view_transform_det && (view_transform_det[m] == -1.0) )
{ /* have to flip normals back */
for ( i = 0 ; i < edgecount+facetcount ; i++ )
for ( j = 0 ; j < 3 ; j++ )
fullarray[i].n[j] *= -1.0;
}
if ( !doing_lazy || !transforms_flag ) break;
} /* end transform loop */
} /* end arrays_flag */
else /* not using display list or arrays */
{
graphgen();
}
glFlush();
auxSwapBuffers();
bailout:
LEAVE_GRAPH_MUTEX;
}
/***********************************************************************
*
* function: display()
*
* purpose: called by Evolver to display on screen.
*/
void display(void)
{ close_flag = 0;
Oglz_start();
InvalidateRect(hwnd,NULL,FALSE); /* generate redraw message */
}
/****************************************************************************
*
* function: make_strips()
*
* purpose: Converts indexed arrays of edges and triangles to strips
* for more efficient plotting.
* Input: global array indexarray
* global variables edgecount,facetcount
* Output: striparray
*/
int ecomp(const void *a, const void *b)
{ int ai = indexarray[edgestart+*(int*)a];
int bi = indexarray[edgestart+*(int*)b];
if ( ai < bi ) return -1;
if ( bi < ai ) return 1;
return 0;
}
struct festruct { int v[3]; /* head and tail and opposite vertices */
int f; /* facet on left */
};
int fecomp ( const struct festruct *a, const struct festruct *b)
{ if ( a->v[0] < b->v[0] ) return -1;
if ( a->v[0] > b->v[0] ) return 1;
if ( a->v[1] < b->v[1] ) return -1;
if ( a->v[1] > b->v[1] ) return 1;
return 0;
}
void make_strips()
{ int *edgeinx; /* oriented edge numbers, sorted by first vertex */
int *evlist; /* vertex indexed list of offsets into edgeinx */
int v;
int i,k,kk;
int *estripno; /* number of current strip */
int *fstripno; /* number of current strip */
int stripnum;
int dataspot;
struct festruct *felist;
int striplength[3]; /* for testing 3 ways from each starting facet */
int *trialstrip; /* for unerasing markings */
int bestlength;
int *bestverts;
int *bestfacets;
int way;
int bestway;
/* strip arrays */
if ( stripdata ) myfree((char*)stripdata);
if ( striparray ) myfree((char*)striparray);
stripdata = (int*)mycalloc(edgecount+facetcount,sizeof(int));
striparray = (struct stripstruct *)mycalloc(edgecount/2+facetcount/3,
sizeof(struct stripstruct));
dataspot = 0; stripnum = 0;
/* edges */
/* make list indexed by vertex */
/* in einx, entry is 2*edgeindex+orientationbit */
edgeinx = (int *)temp_calloc(edgecount,sizeof(int));
for ( i = 0 ; i < edgecount ; i++ )
{ edgeinx[i] = i; } /* using bit for orientation */
qsort((void*)edgeinx,edgecount,sizeof(int),FCAST ecomp);
/* find where individual vertex segments start */
evlist = (int *)temp_calloc(edgecount+1,sizeof(int));
for ( i = 0, v = 0 ; i < edgecount ; i++ )
{ while ( indexarray[edgestart+edgeinx[i]] > v ) evlist[++v] = i;
}
evlist[++v] = i; /* last sentinel */
/* now make strips. start with some edge and just keep going. */
estripno = (int*)temp_calloc(edgecount/2,sizeof(int));
for ( i = 0 ; i < edgecount/2 ; i++ )
{ int nexte,headv;
if ( estripno[i] ) continue;
/* new strip */
striparray[stripnum].mode = GL_LINE_STRIP;
striparray[stripnum].start = dataspot;
nexte = 2*i;
for (;;)
{
estripno[nexte>>1] = stripnum+1;
headv = indexarray[edgestart+(nexte^1)];
stripdata[dataspot++] = headv;
for ( k = evlist[headv] ; k < evlist[headv+1] ; k++ )
{ if ( estripno[edgeinx[k]>>1] == 0 )
{ nexte = edgeinx[k];
break;
}
}
if ( k == evlist[headv+1] ) break; /* end of strip */
}
/* flip list around */
for ( k = striparray[stripnum].start, kk = dataspot-1 ; k < kk ; k++,kk-- )
{ int temp = stripdata[k]; stripdata[k] = stripdata[kk];
stripdata[kk] = temp;
}
/* now backwards */
nexte = 2*i+1;
for (;;)
{
estripno[nexte>>1] = stripnum+1;
headv = indexarray[edgestart+(nexte^1)];
stripdata[dataspot++] = headv;
for ( k = evlist[headv] ; k < evlist[headv+1] ; k++ )
{ if ( estripno[edgeinx[k]>>1] == 0 )
{ nexte = edgeinx[k];
break;
}
}
if ( k == evlist[headv+1] ) break; /* end of strip */
}
striparray[stripnum].count = dataspot - striparray[stripnum].start;
stripnum++;
}
estripcount = stripnum;
temp_free((char*)evlist);
temp_free((char*)estripno);
/* facets */
/* make list of edges with left-hand facets */
felist = (struct festruct *)temp_calloc(facetcount,sizeof(struct festruct));
for ( i = 0, k = 0 ; i < facetcount ; i += 3, k++ )
{ felist[i].v[0] = indexarray[facetstart+i];
felist[i].v[1] = indexarray[facetstart+i+1];
felist[i].v[2] = indexarray[facetstart+i+2];
felist[i].f = k;
felist[i+1].v[0] = indexarray[facetstart+i+1];
felist[i+1].v[1] = indexarray[facetstart+i+2];
felist[i+1].v[2] = indexarray[facetstart+i];
felist[i+1].f = k;
felist[i+2].v[0] = indexarray[facetstart+i+2];
felist[i+2].v[1] = indexarray[facetstart+i];
felist[i+2].v[2] = indexarray[facetstart+i+1];
felist[i+2].f = k;
}
qsort((void*)felist,facetcount,sizeof(struct festruct),FCAST fecomp);
fstripno = (int *)temp_calloc(facetcount/3,sizeof(int));
trialstrip = (int *)temp_calloc(facetcount/3+10,sizeof(int));
bestverts = (int *)temp_calloc(facetcount/3+10,sizeof(int));
bestfacets = (int *)temp_calloc(facetcount/3,sizeof(int));
/* now make strips. start with some facet and just keep going. */
for ( i = 0 ; i < facetcount/3 ; i++ )
{ int nextf,va,vb,vc,whichway;
int firstcount,secondcount; /* for checking orientation at start */
if ( fstripno[i] ) continue;
/* new strip */
striparray[stripnum].mode = GL_TRIANGLE_STRIP;
striparray[stripnum].start = dataspot;
bestlength = 0;
for ( way = 0 ; way < 3 ; way++)
{ int m = 0; /* trialstrip index */
dataspot = striparray[stripnum].start;
nextf = 3*i;
stripdata[dataspot++] = va = indexarray[facetstart+nextf+((1+way)%3)];
stripdata[dataspot++] = vb = indexarray[facetstart+nextf+way];
whichway = 1;
for (;;)
{ struct festruct *fe,key;
//find in felist
if ( whichway ) { key.v[0] = va; key.v[1] = vb; }
else { key.v[1] = va; key.v[0] = vb; }
fe = bsearch(&key,(void*)felist,facetcount,sizeof(struct festruct),
FCAST fecomp);
if ( fe==NULL ) break; // done; maybe hit edge of surface
//see if facet done yet
if ( fstripno[fe->f] != 0 ) break; // done in this direction
//add opposite vertex
vc = fe->v[2];
stripdata[dataspot++] = vc;
fstripno[fe->f] = stripnum+1;
trialstrip[m++] = fe->f;
// ready for next time around
va = vb;
vb = vc;
whichway = !whichway;
}
firstcount = dataspot - striparray[stripnum].start;
/* flip list around */
for ( k = striparray[stripnum].start, kk = dataspot-1 ; k < kk ; k++,kk-- )
{ int temp = stripdata[k]; stripdata[k] = stripdata[kk];
stripdata[kk] = temp;
}
/* now backwards */
va = indexarray[facetstart+nextf+way];
vb = indexarray[facetstart+nextf+((way+1)%3)];
whichway = 1;
for (;;)
{ struct festruct *fe,key;
//find in felist
if ( whichway ) { key.v[0] = va; key.v[1] = vb; }
else { key.v[1] = va; key.v[0] = vb; }
fe = bsearch(&key,(void*)felist,facetcount,sizeof(struct festruct),
FCAST fecomp);
if ( fe==NULL ) break; // done; maybe hit edge of surface
//see if facet done yet
if ( fstripno[fe->f] != 0 ) break; // done in this direction
//add opposite vertex
vc = fe->v[2];
stripdata[dataspot++] = vc;
fstripno[fe->f] = stripnum+1;
trialstrip[m++] = fe->f;
// ready for next time around
va = vb;
vb = vc;
whichway = !whichway;
}
striplength[way] = dataspot - striparray[stripnum].start;
secondcount = striplength[way] - firstcount;
// check orientation at start
if ( firstcount & 1 )
{ if ( secondcount & 1 )
{ striplength[way]--; /* omit last, if necessary */
if ( i == trialstrip[m-1] ) i--; /* so loop doesn't skip omitted facet */
}
/* flip order */
for ( k = striparray[stripnum].start,
kk = striparray[stripnum].start+striplength[way]-1 ; k < kk ; k++,kk-- )
{ int temp = stripdata[k]; stripdata[k] = stripdata[kk];
stripdata[kk] = temp;
}
}
if ( striplength[way] > bestlength )
{ bestlength = striplength[way];
bestway = way;
memcpy(bestverts,stripdata+striparray[stripnum].start,bestlength*sizeof(int));
memcpy(bestfacets,trialstrip,(bestlength-2)*sizeof(int));
}
for ( k = 0 ; k < m ; k++ ) /* unmark */
fstripno[trialstrip[k]] = 0;
} /* end ways */
memcpy(stripdata+striparray[stripnum].start,bestverts,bestlength*sizeof(int));
for ( k = 0 ; k < bestlength-2 ; k++ ) /* remark */
{ fstripno[bestfacets[k]] = stripnum+1;
if ( strip_color_flag && (bestfacets[k] < web.skel[FACET].maxcount) )
set_facet_color(bestfacets[k],(stripnum % 14) + 1);
}
striparray[stripnum].count = bestlength;
dataspot = striparray[stripnum].start + bestlength;
stripnum++;
}
temp_free((char*)evlist);
temp_free((char*)estripno);
temp_free((char*)fstripno);
temp_free((char*)trialstrip);
temp_free((char*)bestverts);
temp_free((char*)bestfacets);
stripcount = stripnum;
fstripcount = stripcount - estripcount;
/* cut down arrays to needed size */
stripdata = (int*)kb_realloc((char*)stripdata,dataspot*sizeof(int));
striparray = (struct stripstruct *)kb_realloc((char*)striparray,
stripcount*sizeof(struct stripstruct));
if ( q_flag )
{ sprintf(msg,"After stripping: %d edgestrips, %d facetstrips\n",
estripcount,fstripcount);
outstring(msg);
}
}
/***************************************************************************
*
* function: hashfunc()
*
* purpose: Compute hash value for vertex.
*/
int hashsize; /* size of hashtable */
int hashfunc(struct vercol *a)
{
int h;
int scale = 100000;
double eps = 3.e-6; /* to prevent coincidences */
h = 15187*(int)(scale*a->x[0]+eps);
h += 4021*(int)(scale*a->x[1]+eps);
h += 2437*(int)(scale*a->x[2]+eps);
h += 7043*(int)(scale*a->n[0]+eps);
h += 5119*(int)(scale*a->n[1]+eps);
h += 8597*(int)(scale*a->n[2]+eps);
h += 1741*(int)(scale*a->c[0]+eps);
h += 4937*(int)(scale*a->c[1]+eps);
h += 1223*(int)(scale*a->c[2]+eps);
h = h % hashsize;
if ( h < 0 ) h += hashsize;
return h;
}
/***************************************************************************
*
* function: make_indexlists()
*
* purpose: Uniquify vertex and edge lists, and create index array for
* OpenGL. Also needed for strips.
*/
void make_indexlists()
{ int i,j;
int rawcount = edgecount+facetcount; /* number of unsorted vertices */
struct vercol **hashlist;
float mat[4][4];
/* get reasonable epsilon for identifying vertices */
glGetFloatv(GL_MODELVIEW_MATRIX,mat[0]);
gleps = 1e-5/sqrt(mat[0][0]*mat[0][0]+mat[0][1]*mat[0][1]
+mat[0][2]*mat[0][2]);
/* Uniquify using hash table */
/* qsort here is a time hog */
if ( indexarray ) myfree((char*)indexarray);
indexarray = (int*)mycalloc(rawcount,sizeof(int));
hashlist = (struct vercol**)temp_calloc(2*rawcount,sizeof(struct vercol *));
hashsize = 2*rawcount;
hashlist[hashfunc(fullarray)] = fullarray;
indexarray[0] = 0;
for ( i = 1, j = 1 ; i < rawcount ; i++ )
{ int h = hashfunc(fullarray+i);
while ( hashlist[h] && vercolcomp(hashlist[h],fullarray+i) )
{ h++; if ( h == hashsize ) h = 0; }
if ( hashlist[h] == NULL ) /* new one */
{
fullarray[j] = fullarray[i];
hashlist[h] = fullarray+j;
j++;
}
indexarray[i] = hashlist[h]-fullarray;
}
temp_free((char*)hashlist);
vertexcount = j;
// Uniquify edges
for ( i = edgestart ; i < edgestart+edgecount ; i += 2 )
{ if ( indexarray[i] > indexarray[i+1] )
{ int temp = indexarray[i];
indexarray[i] = indexarray[i+1];
indexarray[i+1] = temp;
}
}
/* qsort here relatively minor in time */
qsort((void*)(indexarray+edgestart),edgecount/2,2*sizeof(int), FCAST eecomp);
for ( i = 2, j = 0 ; i < edgecount ; i += 2 )
{ if ( eecomp(indexarray+edgestart+i,indexarray+edgestart+j) != 0 )
{ j += 2;
if ( i > j )
{ indexarray[edgestart+j] = indexarray[edgestart+i];
indexarray[edgestart+j+1] = indexarray[edgestart+i+1];
}
}
}
if ( edgecount ) edgecount = j+2;
} /* end make_indexlists() */
evolver-2.30c.dfsg/src/painter.c 0000644 0001753 0001753 00000264624 11410765113 017041 0 ustar hazelsct hazelsct /*************************************************************
* This file is part of the Surface Evolver source code. *
* Programmer: Ken Brakke, brakke@susqu.edu *
*************************************************************/
/*****************************************************************
*
* File: painter.c
*
* Contents: Routines to accumulate and sort facets for display
* back to front. Not device specific, but calls
* device specific routines for actual display.
* Also does transformations on edges.
* painter_end() uses Newell-Newell-Sancha algorithm
* to depth sort and display facets.
* This version uses a separate quadtree of depth-ordered
* lists from the drawing-order list to minimize comparisons
* needed for large elements.
*/
/* Some timings with version 2.18j on starfish31.dmp (2560 facets)
Without visibility test:
Shape Fund. time,sec filesize
Fund 1 0.093 190,829
Cubelet 12 1.08 2,276,025
Cube 48 4.64 9,100,293
Rhomb 96 9.625 18,199,633
With visibility test:
Shape Fund. time,sec filesize
Fund 1 0.165 168,332
Cubelet 12 1.89 1,444,778
Cube 48 9.56 4,456,944
Rhomb 96 24.7 7,162,980
*/
#include "include.h"
static int count; /* number of facets */
static int maxcount; /* number allocated */
struct tsort *trilist; /* list for depth sorting triangles */
static int gdim = 3; /* dimension doing graphics in */
/* results of comparing depth of facets */
#define DISJOINT 1
#define FIRST_BACK 2
#define SECOND_BACK 4
#define ASPLITTINGB 8
#define BSPLITTINGA 16
#define NOTKNOWN 32
#define COPLANAR 64
#define TEXTRA 100
REAL tableau[7][3]; /* simplex tableau */
void pivot ARGS((int ,int ));
int newell_split ARGS((struct tsort *,struct tsort *,struct tsort *,struct tsort *));
int backstamp; /* for timestamping being at back of list */
int plane_test ARGS((struct tsort *,struct tsort *));
int setquadcode ARGS((struct tsort *));
void find_bbox ARGS((struct tsort *));
int separating_line ARGS((struct tsort*,struct tsort*));
int separating_plane ARGS((struct tsort*,struct tsort*,int));
static int ttcompare(t1,t2) /* depth comparison for sort */
struct tsort **t1,**t2;
{
/* First, compare back z */
if ( t1[0]->mins[2] > t2[0]->mins[2] ) return 1;
if ( t1[0]->mins[2] < t2[0]->mins[2] ) return -1;
/* Break ties with front z */
if ( t1[0]->maxs[2] > t2[0]->maxs[2] ) return 1;
if ( t1[0]->maxs[2] < t2[0]->maxs[2] ) return -1;
/* Finally, break ties with id to get consistent ordering,
independent of how many elements are being sorted */
if ( t1[0]->f_id > t2[0]->f_id ) return 1;
if ( t1[0]->f_id < t2[0]->f_id ) return -1;
return 0;
}
/* quadtree of depth lists */
struct qtree_t { struct tsort *depthhead;
float maxdepth; /* of all in subtree */
} *qtree;
int maxquaddepth = 8; /* maximum depth of quadtree */
int get_quadindex ARGS((unsigned int));
void qdepth_insert ARGS((struct tsort *));
struct tsort *search_subtree ARGS((int,struct tsort *,int *));
/* visibility stuff */
void visibility_stage ARGS((struct tsort *));
void visibility_end ARGS((void));
int vis_count; /* used structures */
int vis_max; /* allocated structures */
struct tsort *vis_list; /* storage */
/*****************************************************************
*
* Function: find_bbox()
*
* Purpose: find 3D bounding box for edge or facet.
*
*/
void find_bbox(t)
struct tsort *t;
{ int n;
REAL dx,dy,len;
if ( (t->flag & 0xF) == EDGE )
{
if ( t->flag & EDGE_ARC )
{ REAL w1[MAXCOORD],w2[MAXCOORD],mag1,mag2,w1w2,center[2],radius;
REAL det,angle1,angle2;
int i;
for (i = 0 ; i < SDIM ; i++ )
{ w1[i] = t->x[1][i] - t->x[0][i];
w2[i] = t->x[2][i] - t->x[0][i];
}
det = w1[0]*w2[1] - w1[1]*w2[0];
mag1 = SDIM_dot(w1,w1); mag2 = SDIM_dot(w2,w2);
w1w2 = w1[0]*w2[0] + w1[1]*w2[1];
for ( n = 0 ; n < gdim ; n++ )
{ /* endpoints first */
if ( t->x[0][n] < t->x[2][n] )
{ t->maxs[n] = t->x[2][n];
t->mins[n] = t->x[0][n];
}
else
{ t->maxs[n] = t->x[0][n];
t->mins[n] = t->x[2][n];
}
}
if ( 4000*det*det > mag1*mag1*mag2 + mag1*mag2*mag2 - 2*mag1*w1w2*mag2 )
{ /* circle rather that straight line */
center[0] = t->x[0][0] + 0.5*(w2[1]*mag1 - w1[1]*mag2)/det;
center[1] = t->x[0][1] + 0.5*(-w2[0]*mag1 + w1[0]*mag2)/det;
radius = sqrt((mag1*mag1*mag2+mag1*mag2*mag2-2*mag1*w1w2*mag2)
/4/det/det);
angle1 = atan2(t->x[0][1]-center[1],t->x[0][0]-center[0]);
angle2 = atan2(t->x[2][1]-center[1],t->x[2][0]-center[0]);
if ( det < 0 )
{ REAL temp = angle1; angle1 = angle2; angle2 = temp; }
if ( angle2 < angle1 ) angle2 += 2*M_PI;
if ( (angle1 < 0.0 && angle2 > 0.0 ) ||
(angle1 < 2*M_PI && angle2 > 2*M_PI) )
t->maxs[0] = (float)(center[0] + radius);
if ( (angle1 < M_PI && angle2 > M_PI ) ||
(angle1 < 3*M_PI && angle2 > 3*M_PI) )
t->mins[0] = (float)(center[0] - radius);
if ( (angle1 < M_PI/2 && angle2 > M_PI/2 ) ||
(angle1 < 5*M_PI/2 && angle2 > 5*M_PI/2) )
t->maxs[1] = (float)(center[1] + radius);
if ( (angle1 < -M_PI/2 && angle2 > -M_PI/2 ) ||
(angle1 < 3*M_PI/2 && angle2 > 3*M_PI/2) )
t->mins[1] = (float)(center[1] - radius);
return;
}
} /* end EDGE_ARC */
else /* just a straight segment */
for ( n = 0 ; n < gdim ; n++ )
{ if ( t->x[0][n] < t->x[1][n] )
{ t->maxs[n] = t->x[1][n];
t->mins[n] = t->x[0][n];
}
else
{ t->maxs[n] = t->x[0][n];
t->mins[n] = t->x[1][n];
}
}
/* adjust extents for thickness */
dx = fabs(t->x[1][0] - t->x[0][0]);
dy = fabs(t->x[1][1] - t->x[0][1]);
len = sqrt(dx*dx+dy*dy);
if ( len > 0.0 )
{ t->maxs[0] += (float)(dy/len*t->width/2);
t->mins[0] -= (float)(dy/len*t->width/2);
t->maxs[1] += (float)(dx/len*t->width/2);
t->mins[1] -= (float)(dx/len*t->width/2);
}
return;
} /* end EDGE */
/* facet */
for ( n = 0 ; n < gdim ; n++ )
{ if ( t->x[0][n] < t->x[1][n] )
{ if ( t->x[2][n] < t->x[0][n] )
{ t->maxs[n] = t->x[1][n];
t->mins[n] = t->x[2][n];
}
else if ( t->x[1][n] < t->x[2][n] )
{ t->maxs[n] = t->x[2][n];
t->mins[n] = t->x[0][n];
}
else
{ t->maxs[n] = t->x[1][n];
t->mins[n] = t->x[0][n];
}
}
else
{ if ( t->x[2][n] < t->x[1][n] )
{ t->maxs[n] = t->x[0][n];
t->mins[n] = t->x[2][n];
}
else if ( t->x[0][n] < t->x[2][n] )
{ t->maxs[n] = t->x[2][n];
t->mins[n] = t->x[1][n];
}
else
{ t->maxs[n] = t->x[0][n];
t->mins[n] = t->x[1][n];
}
}
}
}
/* For setting quadtree code and checking if in bounding box. */
/* Coded for 32 bit ints. */
#define OUTOFBOX 0
#define INTHEBOX 1
int setquadcode(t)
struct tsort *t;
{ unsigned int q = 0; /* the quadcode */
unsigned int bit = 1; /* for shifting to quad bit position */
int n;
REAL midx = (minclipx+maxclipx)/2;
REAL midy = (minclipy+maxclipy)/2;
REAL deltax = (maxclipx-minclipx)/4;
REAL deltay = (maxclipy-minclipy)/4;
if ( t->maxs[0] < minclipx || t->mins[0] > maxclipx || t->maxs[1] < minclipy
|| t->mins[1] > maxclipy ) return OUTOFBOX;
for ( n = 0 ; n < 8 ; n++, deltax /= 2, deltay /= 2 )
{
if ( t->maxs[0] <= midx )
{ q |= bit; midx -= deltax; }
else if ( t->mins[0] >= midx )
{ q |= bit<<1; midx += deltax; }
else break;
bit <<= 2;
if ( t->maxs[1] <= midy )
{ q |= bit; midy -= deltay; }
else if ( t->mins[1] >= midy )
{ q |= bit<<1; midy += deltay; }
else break;
bit <<= 2;
}
t->quadcode = q;
return INTHEBOX;
}
void painter_start()
{ int dummy;
long allocsize;
gdim = (SDIM <= 3) ? SDIM : 3;
/* allocate space for depth sort list */
if ( web.representation == STRING )
{ maxcount = web.skel[EDGE].count + 5;
if ( web.torus_flag ) maxcount *= 2;
}
else
{ if ( web.torus_flag )
if ( torus_display_mode == TORUS_CLIPPED_MODE )
maxcount = 5*web.skel[FACET].count+ bare_edge_count + 5;
else maxcount = 2*web.skel[FACET].count+ bare_edge_count + 5;
else
maxcount = web.skel[FACET].count + bare_edge_count + 5;
}
if ( transforms_flag ) maxcount *= transform_count;
if ( web.dimension > 2 )
maxcount *= web.dimension+1; /* each simplex face becomes facet */
allocsize = (long)maxcount*sizeof(struct tsort);
if ( allocsize >= MAXALLOC )
maxcount = MAXALLOC/sizeof(struct tsort);
trilist = (struct tsort *)temp_calloc(maxcount,sizeof(struct tsort));
count = 0;
vis_count = 0;
vis_list = NULL;
vis_max = 0;
backstamp = 0;
ps_widthattr = find_extra(PS_WIDTHNAME,&dummy);
}
void painter_edge(gdata,e_id)
struct graphdata *gdata;
edge_id e_id;
{
struct tsort *t;
int i,j;
REAL a[MAXCOORD+1],b[MAXCOORD+1];
REAL dx,dy,dz,mag,width;
int ctrl_pts = gdata[0].flags & EDGE_ARC ? 3 : 2;
if ( gdata->color == CLEAR ) return;
if ( count >= maxcount-2 )
{ trilist = (struct tsort *)temp_realloc((char*)trilist,
(maxcount+200)*sizeof(struct tsort));
maxcount += 200;
}
t = trilist + count;
t->flag = EDGE;
t->flag |= (gdata->flags & (EDGE_ARC|LABEL_EDGE|LABEL_HEAD|LABEL_TAIL));
for ( j = SDIM ; j < HOMDIM-1 ; j++ ) a[j] = 0.0; /* filler */
for ( i = 0 ; i < ctrl_pts ; i++ )
{
for ( j = 0 ; (j < SDIM) && (j < HOMDIM-1) ; j++ )
a[j] = gdata[i].x[j];
a[HOMDIM-1] = 1.0;
matvec_mul(view,a,b,HOMDIM,HOMDIM); /* transform */
if ( SDIM <= 2 )
for ( j = 0 ; j < 3 ; j++ ) t->x[i][j] = (float)b[j];
else for ( j = 0 ; j < 3 ; j++ ) t->x[i][j] = (float)b[(j+1)%3];
t->x[i][2] += (float).0001; /* bias edges in front of facets */
}
/* width of edge, in descending order of thickness */
if ( ps_widthattr >= 0 )
width = *EREAL(t->f_id,ps_widthattr);
else if ( gdata->etype & BARE_EDGE ) width = ps_bareedgewidth;
else if ( gdata->etype & FIXED_EDGE ) width = ps_fixededgewidth;
else if ( gdata->etype & CONSTRAINT_EDGE ) width = ps_conedgewidth;
else if ( gdata->etype & BOUNDARY_EDGE ) width = ps_conedgewidth;
else if ( gdata->etype & SINGLE_EDGE ) width = ps_stringwidth;
else if ( gdata->etype & TRIPLE_EDGE ) width = ps_tripleedgewidth;
else width = ps_gridedgewidth; /* regular grid interior edge */
t->width = (float)width;
t->f_id = e_id;
t->color = t->ecolor[0] = gdata->ecolor;
t->etype[0] = gdata->etype;
/* find extents */
find_bbox(t);
/* normal vector, closest to z axis */
dx = t->x[1][0] - t->x[0][0];
dy = t->x[1][1] - t->x[0][1];
dz = t->x[1][2] - t->x[0][2];
t->normal[0] = (float)(dx*dz);
t->normal[1] = (float)(dy*dz);
t->normal[2] = -(float)(dx*dx+dy*dy);
mag = sqrt(dotf(t->normal,t->normal,3));
if ( mag != 0.0 )
for ( i = 0 ; i < 3; i++ ) t->normal[i] /= (float)mag;
if ( setquadcode(t) == OUTOFBOX ) return;
count++;
}
void painter_facet(gdata,f_id)
struct graphdata *gdata;
facet_id f_id;
{
int i,j;
REAL a[MAXCOORD+1],b[FACET_VERTS][MAXCOORD+1];
struct tsort *t;
REAL normal[MAXCOORD],mag;
if ( gdata[0].color == UNSHOWN )
{ /* just do edges */
struct graphdata ggdata[2];
facetedge_id fe=NULLID;
if ( valid_id(f_id) )
fe = get_facet_fe(f_id);
for ( i = 0 ; i < FACET_EDGES ; i++ )
{ if ( (gdata[i].etype&EBITS) == INVISIBLE_EDGE ) continue;
ggdata[0] = gdata[i];
ggdata[0].color = gdata[i].ecolor;
ggdata[1] = gdata[i==2 ? 0 : i+1];
if ( valid_id(fe) )
{ painter_edge(ggdata,get_fe_edge(fe));
fe = get_next_edge(fe);
}
else painter_edge(ggdata,NULLID);
}
return;
}
if ( count >= maxcount )
{ trilist = (struct tsort *)temp_realloc((char*)trilist,
(maxcount+200)*sizeof(struct tsort));
maxcount += 200;
}
t = trilist + count;
t->flag = FACET | (gdata->flags&LABEL_FACET);
t->f_id = f_id;
t->color = gdata[0].backcolor; /* not sure why, but works */
for ( i = 0 ; i < FACET_EDGES ; i++ )
{ t->ecolor[i] = gdata[i].ecolor;
t->etype[i] = gdata[i].etype;
t->v_id[i] = gdata[i].v_id;
}
/* accumulate list of triangles to display */
for ( j = SDIM ; j < HOMDIM-1 ; j++ ) a[j] = 0.0;
for ( i = 0 ; i < FACET_VERTS ; i++ )
{
for ( j = 0 ; (j < SDIM) && (j < HOMDIM-1) ; j++ )
a[j] = gdata[i].x[j];
a[HOMDIM-1] = 1.0;
matvec_mul(view,a,b[i],HOMDIM,HOMDIM); /* transform */
if ( SDIM <= 2 )
{ t->x[i][0] = (float)b[i][0];
t->x[i][1] = (float)b[i][1];
}
else
{ t->x[i][0] = (float)b[i][1];
t->x[i][1] = (float)b[i][2];
t->x[i][2] = (float)b[i][0];
}
}
if ( SDIM <= 2 )
{ t->normal[0] = t->normal[1] = 0.0;
t->normal[2] = 1.0;
}
else
{ vnormal(b[0],b[1],b[2],normal);
mag = sqrt(SDIM_dot(normal,normal));
if ( mag > 0.0 )
{ t->normal[0] = (float)(normal[1]/mag);
t->normal[1] = (float)(normal[2]/mag);
t->normal[2] = (float)(normal[0]/mag);
if ( fabs(t->normal[2]) < 1e-6 ) t->normal[2] = 0.0;
} else
{ t->normal[0] = 0.0f;
t->normal[1] = 0.0f;
t->normal[2] = 1.0f;
}
}
if ( t->normal[2] > (float)0.0 ) /* frontward normal */
{ int c;
vertex_id tv;
for ( i = 0 ; i < gdim ; i++ )
{ float temp = (float)t->x[1][i];
t->x[1][i] = t->x[2][i];
t->x[2][i] = temp;
t->normal[i] = -t->normal[i];
}
c = t->ecolor[0];
t->ecolor[0] = t->ecolor[2];
t->ecolor[2] = c;
c = t->etype[0] ^ LABEL_REVERSED;
t->etype[0] = t->etype[2] ^ LABEL_REVERSED;
t->etype[2] = (short)c;
t->etype[1] ^= LABEL_REVERSED;
t->color = gdata[0].color;
tv = t->v_id[1];
t->v_id[1] = t->v_id[2];
t->v_id[2] = tv;
t->flag |= FLIPPED_FACET;
}
else
{
if ( backcull_flag && (gdata[0].color == gdata[0].backcolor) ) return;
}
/* find extents */
find_bbox(t);
if ( setquadcode(t) == OUTOFBOX ) return;
count++;
}
/* stats for analyzing performance; REAL to handle large counts */
REAL in_back_calls;
REAL box_overlaps;
REAL facetfacet;
REAL facetedge;
REAL edgeedge;
REAL crossings;
REAL swaps;
REAL done;
REAL loopbailouts;
REAL sep_line_calls;
REAL sep_plane_calls;
struct tsort **tlist;
/*struct tsort *depthhead;*/
/*************************************************************************
*
* function: search_subtree()
*
* purpose: search node and subtree of quadtree depth lists for an
* element obscured by given element.
* return: pointer to obscured element, or NULL if none found.
* also retval to indicate type of relationship
*/
struct tsort *search_subtree(qinx,tk,retval)
int qinx; /* index of node in quadtree */
struct tsort *tk; /* given element */
int *retval;
{ struct tsort *tj;
*retval = 0;
/* check overall subtree max depth */
if ( tk->maxs[2] <= qtree[qinx].maxdepth )
return NULL;
/* the node itself */
for ( tj = qtree[qinx].depthhead ; tj != NULL ; tj = tj->next )
{
if ( tj == tk ) continue;
if ( tk->maxs[2] <= tj->mins[2] )
break;
*retval = in_back(tk,tj);
if ( *retval & (FIRST_BACK|COPLANAR|DISJOINT) ) continue;
return tj;
}
/* one child */
tj = search_subtree(2*qinx,tk,retval);
if ( tj ) return tj;
/* other child */
return search_subtree(2*qinx+1,tk,retval);
}
#ifdef XXXXX
/* for debugging */
void loopchecker()
{ int counter;
int qinx;
int i;
for ( i = 0 ; i < count+TEXTRA ; i++ )
if ( tlist[i]->spot != i )
kb_error(2893,"Bad spot\n",RECOVERABLE);
for ( qinx = 0 ; qinx < 0x40000 ; qinx++ )
{ struct tsort *tj;
int q;
struct tsort *slowboat = qtree[qinx].depthhead; /* likewise */
struct tsort *prev = NULL;
if ( slowboat == NULL ) continue;
counter = 0; q = slowboat->quadcode;
if ( qinx != get_quadindex(q) )
kb_error(2585,"Bad qinx.\n",RECOVERABLE);
for ( tj = qtree[qinx].depthhead ; tj != NULL ; prev=tj,tj = tj->next )
{ /* loop detection */
if ( tj->prev != prev )
kb_error(2892,"bad prev\n",RECOVERABLE);
if ( tj->quadcode != q )
kb_error(2891,"Bad qinx.\n",RECOVERABLE);
if ( counter & 1) slowboat = slowboat->next;
if ( (slowboat == tj) && (counter > 1) )
kb_error(2591,"Internal error: loop in loopchecker()\n",
RECOVERABLE);
counter++;
}
}
}
#endif
/**************************************************************************
*
* function: painter_end()
*
* purpose: sort and display facets and edges from trilist.
*/
/* for debugging; just displays list as is after given number of facets */
int debug_k = 0x7FFFFFFF;
void painter_end()
{
int k;
int loopcount; /* for emergency loop bailout */
struct tsort **ll,*tt;
int quadalloc;
int k_top; /* top of tlist */
struct tsort textra[TEXTRA]; /* for triangle fragments */
in_back_calls = box_overlaps = facetfacet = facetedge = edgeedge =
crossings = sep_plane_calls = sep_line_calls = 0;
loopbailouts = 0;
if ( count > maxcount ) count = maxcount; /* in case there was excess */
/* find bounding box */
if ( need_bounding_box )
{ struct tsort *t;
bbox_minx = bbox_miny = 1e20;
bbox_maxx = bbox_maxy = -1e20;
for ( k = 0, t = trilist ; k < count ; k++,t++ )
{ if ( t->mins[0] < bbox_minx ) bbox_minx = (REAL)t->mins[0];
if ( t->mins[1] < bbox_miny ) bbox_miny = (REAL)t->mins[1];
if ( t->maxs[0] > bbox_maxx ) bbox_maxx = (REAL)t->maxs[0];
if ( t->maxs[1] > bbox_maxy ) bbox_maxy = (REAL)t->maxs[1];
}
}
(*init_graphics)();
if ( SDIM == 2 ) /* don't bother with depth */
{ for ( k = 0 ; k < count ; k++ )
visibility_stage(trilist+k);
goto end_exit;
}
/* now sort on min z, moving pointers instead of structures */
/* leaving room at front of list for extra fragments */
tlist = (struct tsort **)temp_calloc(count+TEXTRA,sizeof(struct tsort *));
for ( k = 0, ll=tlist+TEXTRA, tt=trilist ; k < count ; k++ ) *(ll++) = tt++;
qsort((char *)(tlist+TEXTRA),count,sizeof(struct tsort *),FCAST ttcompare);
for ( k = 0 ; k < TEXTRA ; k++ )
{ tlist[k] = textra+k; tlist[k]->spot = k; tlist[k]->flag = 0; }
for ( k = TEXTRA ; k < TEXTRA+count ; k++ )
tlist[k]->spot = k;
/* quadtree of depth lists */
maxquaddepth = 8; /* maybe make this adjustable later */
quadalloc = 2 << (2*maxquaddepth + 1);
qtree = (struct qtree_t *)temp_calloc(quadalloc,sizeof(struct qtree_t));
for ( k = 0 ; k < quadalloc ; k++ )
qtree[k].maxdepth = 1e30f;
for ( k = count+TEXTRA-1 ; k >= TEXTRA ; k-- )
qdepth_insert(tlist[k]);
/* display */
loopcount = 0;
k_top = count+TEXTRA;
for ( k = TEXTRA ; k < k_top ; )
{ struct tsort *tk = tlist[k];
struct tsort *tj;
int sinx,qinx=0;
int retval;
if ( breakflag ) break;
if ( !tk->flag ) { k++; continue; }
/* for debugging and testing */
if ( k > debug_k )
goto draw_it;
/* tk is current candidate back facet */
/* search quadtree list for any z overlap */
/* First, node to root */
qinx = get_quadindex(tk->quadcode);
for ( sinx = qinx >> 1 ; sinx != 0 ; sinx >>= 1 )
{ for ( tj = qtree[sinx].depthhead ; tj != NULL ; tj = tj->next )
{
if ( tj == tk ) continue;
if ( tk->maxs[2] <= tj->mins[2] )
break;
retval = in_back(tk,tj);
if ( retval & (FIRST_BACK|COPLANAR|DISJOINT) ) continue;
goto have_conflict;
}
}
/* now search subtree for conflicts */
tj = search_subtree(qinx,tk,&retval);
if ( tj==NULL ) goto draw_it;
have_conflict:
/* Now have conflict, tk obscuring tj */
/* test for possible looping, and if found, split tk */
if ( (tj->backstamp == backstamp) )
{ int ret;
crossings++;
if ( ++loopcount > count )
{ loopbailouts++; goto draw_it; }
/* need to split */
if ( k < 2 )
{ /* not enough room, so expand tlist allocation, with free at start */
int newsize = 2*k_top;
int n;
struct tsort *more = (struct tsort*)temp_calloc(k_top,sizeof(struct tsort));
tlist = (struct tsort**)temp_realloc((char*)tlist,newsize*sizeof(struct tsort*));
for ( n = 0 ; n < k_top ; n++ )
{ tlist[n+k_top] = tlist[n];
tlist[n] = more+n;
}
for ( n = 0 ; n < newsize ; n++ )
tlist[n]->spot = n;
k += k_top;
k_top = newsize;
}
if( retval & BSPLITTINGA )
{
ret = newell_split(tk,tj,tlist[k-1],tlist[k-2]);
if ( ret )
{
k -= ret;
goto repeat_tests; /* might not have split */
}
}
else if ( retval & ASPLITTINGB )
{
/* try splitting the other way */
ret = newell_split(tj,tk,tlist[k-1],tlist[k-2]);
if ( ret )
{ k -= ret;
goto repeat_tests;
}
}
else if ( ((tk->flag & 0xF) == EDGE) && ((tj->flag & 0xF) == EDGE) )
{
ret = newell_split(tk,tj,tlist[k-1],tlist[k-2]);
if ( ret )
{
k -= ret;
goto repeat_tests; /* might not have split */
}
}
}
tk->backstamp = backstamp;
/* swap tj and tk */
tlist[k] = tj;
tlist[tj->spot] = tk;
tk->spot = tj->spot;
tj->spot = k;
swaps++;
goto repeat_tests;
draw_it:
visibility_stage(tk);
loopcount = 0;
tk->flag = 0; /* to indicate empty structure */
/* remove from depth list */
if ( tk == qtree[qinx].depthhead )
qtree[qinx].depthhead = tk->next;
sinx = qinx;
/* fix up subtree maxdepths */
while ( sinx && ( tk->mins[2] <= qtree[sinx].maxdepth ) )
{ float maxd = 1e30f;
if ( qtree[sinx].depthhead )
maxd = qtree[sinx].depthhead->mins[2];
if ( sinx < (1 << (2*maxquaddepth)) )
{ if ( maxd > qtree[2*sinx].maxdepth )
maxd = qtree[2*sinx].maxdepth;
if ( maxd > qtree[2*sinx+1].maxdepth )
maxd = qtree[2*sinx+1].maxdepth;
}
qtree[sinx].maxdepth = maxd;
sinx >>= 1;
}
if ( tk->prev ) tk->prev->next = tk->next;
if ( tk->next ) tk->next->prev = tk->prev;
repeat_tests:
continue;
}
end_exit:
if ( verbose_flag )
{
printf("in_back_calls: %g\n",in_back_calls);
printf(" facetfacet: %g\n",facetfacet);
printf(" facetedge: %g\n",facetedge);
printf(" edgeedge: %g\n",edgeedge);
printf("box_overlaps: %g\n",box_overlaps);
printf("sep_line_calls: %g\n",sep_line_calls);
printf("sep_plane_calls: %g\n",sep_plane_calls);
printf("crossings: %g\n",crossings);
printf("swaps: %g\n",swaps);
printf("loop bailouts: %g\n",loopbailouts);
}
if ( tlist ) temp_free((char *)tlist);
if ( qtree ) temp_free((char *)qtree);
temp_free((char *)trilist); trilist = NULL;
if ( visibility_test )
visibility_end();
(*finish_graphics)();
} /* end old painter_end() */
/*********************************************************************
*
* function: in_back()
*
* purpose: see if one facet or edge obscures another.
*
* returns DISJOINT, FIRST_BACK, SECOND_BACK, ASPLITTINGB, BSPLITTINGA,
* or COPLANAR (possibly bitwise OR)
*/
int in_back(ta,tb)
struct tsort *ta,*tb;
{
int n;
int retval;
if ( verbose_flag )
{
in_back_calls++;
if ( (ta->flag & 0xF) == FACET )
{ if ( (tb->flag & 0xF) == FACET )
facetfacet++;
else facetedge++;
}
else
{ if ( (tb->flag & 0xF) == FACET )
facetedge++;
else edgeedge++;
}
}
/* quick test with quadcodes */
if ( ((ta->quadcode & tb->quadcode) != ta->quadcode) &&
((ta->quadcode & tb->quadcode) != tb->quadcode) )
return DISJOINT;
/* test x and y extent overlap */
for ( n = 0 ; n < 2 ; n++ )
if ( (tb->maxs[n] <= ta->mins[n]) || (tb->mins[n] >= ta->maxs[n]) )
return DISJOINT;
if ( ta->maxs[2] <= tb->mins[2] ) return FIRST_BACK;
box_overlaps++; /* for verbose stats */
if ( separating_line(ta,tb) == DISJOINT ) return DISJOINT;
retval = plane_test(ta,tb);
if ( retval & (FIRST_BACK|COPLANAR|DISJOINT) ) return retval;
/* now the nitty gritty check to see if they overlap */
#ifdef ZZZ
if ( (ta->flag & 0xF) == FACET )
{ if ( (tb->flag & 0xF) == FACET )
return facetfacetcompare(ta,tb);
else
{ retval = edgefacetcompare(tb,ta);
if ( retval & (FIRST_BACK|SECOND_BACK) )
return retval ^ (FIRST_BACK|SECOND_BACK);
else return retval;
}
}
else
{ if ( (tb->flag & 0xF) == FACET )
return edgefacetcompare(ta,tb);
else
{ retval = edgeedgecompare(tb,ta);
if ( retval & (FIRST_BACK|SECOND_BACK) )
return retval ^ (FIRST_BACK|SECOND_BACK);
else return retval;
}
}
#endif
return retval;
}
/**************************************************************************
*
* function: get_quadindex()
*
* purpose: convert quadcode to index number in quadtree list.
*
*/
int get_quadindex(q)
unsigned int q;
{ int inx,k;
inx = 1;
for ( k = 0 ; k < 2*maxquaddepth ; k++, q >>= 2 )
{ int bits = q & 0x3;
if ( bits == 0 ) return inx;
inx <<= 1;
if ( bits == 2 )
inx++;
}
return inx;
}
/**************************************************************************
*
* function: qdepth_insert()
*
* purpose: insert new fragment in proper place in quadtree depth list.
* For now, crude linear search.
*/
void qdepth_insert(tc)
struct tsort *tc;
{ struct tsort *prev,*next;
int qinx = get_quadindex(tc->quadcode);
int sinx;
/* take care of maxdepths of subtrees */
sinx = qinx;
while ( sinx && (tc->mins[2] < qtree[sinx].maxdepth) )
{ qtree[sinx].maxdepth = tc->mins[2];
sinx >>= 1;
}
prev = NULL;
for ( next=qtree[qinx].depthhead; next != NULL; prev=next, next=next->next )
{
if ( tc->mins[2] < next->mins[2] )
{ tc->next = next;
tc->prev = prev;
if ( prev )
prev->next = tc;
else qtree[qinx].depthhead = tc;
next->prev = tc;
goto qdepth_insert_exit;
}
}
/* at end of list */
if ( prev ) prev->next = tc;
else qtree[qinx].depthhead = tc;
tc->next = NULL;
tc->prev = prev;
qdepth_insert_exit:;
}
/*************************************************************************
*
* function: newell_split()
*
* purpose: split one triangle by plane of another.
*
* return: number of new elements generated.
*/
int newell_split(ta,tb,tc,td)
struct tsort *ta; /* splittee and fragment return */
struct tsort *tb; /* splitter */
struct tsort *tc; /* fragment return */
struct tsort *td; /* fragment return */
{
int i;
REAL d0,d1,d2,db;
int retval;
int tmpspot;
backstamp++; /* clear loop indications */
if ( (tb->flag & 0xF) == EDGE )
{ struct tsort *t;
if ( (ta->flag & 0xF) == EDGE )
{ /* cut first edge in half */
tmpspot = tc->spot; *tc = *ta; tc->spot = tmpspot;
for ( i = 0 ; i < gdim ; i++ )
{ float mid = (ta->x[0][i] + ta->x[1][i])/2;
if ( ta->x[0][2] > ta->x[1][2] ) /* ta is back half */
{ ta->x[0][i] = mid; tc->x[1][i] = mid; }
else { ta->x[1][i] = mid; tc->x[0][i] = mid; }
}
for ( i = 0 ; i < gdim ; i++ )
{ ta->mins[i] = (ta->x[0][i]x[1][i]) ? ta->x[0][i] : ta->x[1][i];
tc->mins[i] = (tc->x[0][i]x[1][i]) ? tc->x[0][i] : tc->x[1][i];
ta->maxs[i] = (ta->x[0][i]>ta->x[1][i]) ? ta->x[0][i] : ta->x[1][i];
tc->maxs[i] = (tc->x[0][i]>tc->x[1][i]) ? tc->x[0][i] : tc->x[1][i];
}
/* find_bbox(tc); */
if ( setquadcode(tc) == INTHEBOX )
{ qdepth_insert(tc);
return 1;
}
else { tc->flag = 0; return 0; }
}
t = ta; ta = tb; tb = t; /* swap so edge first */
}
if ( (ta->flag & 0xF) == EDGE ) /* tb assumed to be facet */
{
db = dotf(tb->normal,tb->x[0],gdim);
d0 = dotf(tb->normal,ta->x[0],gdim);
d1 = dotf(tb->normal,ta->x[1],gdim);
/* fill in fragment info */
tmpspot = tc->spot; *tc = *ta; tc->spot = tmpspot;
for ( i = 0 ; i < gdim ; i++ )
{ double mid = (((db-d0)*ta->x[1][i] + (d1-db)*ta->x[0][i])/(d1-d0));
if ( ta->x[0][2] < ta->x[1][2] ) /* keep ta as back part */
ta->x[1][i] = tc->x[0][i] = (float)mid;
else ta->x[0][i] = tc->x[1][i] = (float)mid;
}
for ( i = 0 ; i < gdim ; i++ )
{ ta->mins[i] = (ta->x[0][i]x[1][i]) ? ta->x[0][i] : ta->x[1][i];
tc->mins[i] = (tc->x[0][i]x[1][i]) ? tc->x[0][i] : tc->x[1][i];
ta->maxs[i] = (ta->x[0][i]>ta->x[1][i]) ? ta->x[0][i] : ta->x[1][i];
tc->maxs[i] = (tc->x[0][i]>tc->x[1][i]) ? tc->x[0][i] : tc->x[1][i];
}
/* find_bbox(tc); */
if ( setquadcode(tc) == INTHEBOX )
{ qdepth_insert(tc);
return 1;
}
else { tc->flag = 0; return 0; }
}
/* figure out which vertices of ta on same side, and get as 0,1 */
db = dotf(tb->normal,tb->x[0],gdim);
d0 = dotf(tb->normal,ta->x[0],gdim);
d1 = dotf(tb->normal,ta->x[1],gdim);
d2 = dotf(tb->normal,ta->x[2],gdim);
if ( (d0db) && (d1>db) && (d2>db) )
{ return 0; }
retval = 0;
if ( db == d0 ) /* split thru vertex 0 of ta */
{
tmpspot = tc->spot; *tc = *ta; tc->spot = tmpspot;
/* fill in fragment info */
for ( i = 0 ; i < gdim ; i++ )
{ ta->x[2][i] = tc->x[1][i] =
(float)(((db-d1)*ta->x[2][i] + (d2-db)*ta->x[1][i])/(d2-d1));
}
/* internal edges invisible */
ta->etype[2] = tc->etype[0] = SPLITTING_EDGE;
retval = 1;
}
if ( db == d1 ) /* split thru vertex 1 of ta */
{
tmpspot = tc->spot; *tc = *ta; tc->spot = tmpspot;
/* fill in fragment info */
for ( i = 0 ; i < gdim ; i++ )
{ ta->x[2][i] = tc->x[0][i] =
(float)(((db-d0)*ta->x[2][i] + (d2-db)*ta->x[0][i])/(d2-d0));
}
/* internal edges invisible */
ta->etype[1] = tc->etype[0] = SPLITTING_EDGE;
retval = 1;
}
if ( db == d2 ) /* split thru vertex 2 of ta */
{
tmpspot = tc->spot; *tc = *ta; tc->spot = tmpspot;
/* fill in fragment info */
for ( i = 0 ; i < gdim ; i++ )
{ ta->x[1][i] = tc->x[0][i] =
(float)(((db-d0)*ta->x[1][i] + (d1-db)*ta->x[0][i])/(d1-d0));
}
/* internal edges invisible */
ta->etype[1] = tc->etype[2] = SPLITTING_EDGE;
retval = 1;
}
if ( retval == 1 )
{
/* set mins and maxs */
for ( i = 0 ; i < gdim ; i++ )
{ int j;
ta->mins[i] = tc->mins[i] = (float)1e30;
ta->maxs[i] = tc->maxs[i] = (float)(-1e30);
for ( j = 0 ; j < FACET_VERTS ; j++ )
{ if ( ta->x[j][i] < ta->mins[i] ) ta->mins[i] = ta->x[j][i];
if ( tc->x[j][i] < tc->mins[i] ) tc->mins[i] = tc->x[j][i];
if ( ta->x[j][i] > ta->maxs[i] ) ta->maxs[i] = ta->x[j][i];
if ( tc->x[j][i] > tc->maxs[i] ) tc->maxs[i] = tc->x[j][i];
}
}
if ( ta->mins[2] > tc->mins[2] )
{ struct tsort tmp; /* get ta as back part */
tmp = *ta;
*ta = *tc;
*tc = tmp;
tmpspot = ta->spot; ta->spot = tc->spot; tc->spot = tmpspot;
}
/* find_bbox(tc); */
if ( setquadcode(tc) == INTHEBOX )
{ qdepth_insert(tc);
return 1;
}
else { tc->flag = 0; return 0; }
}
if ( (d0-db)*(d2-db) > 0.0 )
{ int c = ta->ecolor[1];
short e = ta->etype[1];
REAL d = d1;
for ( i = 0 ; i < gdim ; i++ )
{ float temp = ta->x[1][i];
ta->x[1][i] = ta->x[0][i]; ta->x[0][i] = ta->x[2][i];
ta->x[2][i] = temp;
}
ta->ecolor[1] = ta->ecolor[0]; ta->ecolor[0] = ta->ecolor[2];
ta->ecolor[2] = c;
ta->etype[1] = ta->etype[0]; ta->etype[0] = ta->etype[2];
ta->etype[2] = e;
d1 = d0; d0 = d2; d2 = d;
}
else if ( (d1-db)*(d2-db) > 0.0 )
{ int c = ta->ecolor[1];
short e = ta->etype[1];
REAL d = d1;
for ( i = 0 ; i < gdim ; i++ )
{ float temp = ta->x[1][i];
ta->x[1][i] = ta->x[2][i]; ta->x[2][i] = ta->x[0][i];
ta->x[0][i] = temp;
}
ta->ecolor[1] = ta->ecolor[2]; ta->ecolor[2] = ta->ecolor[0];
ta->ecolor[0] = c;
ta->etype[1] = ta->etype[2]; ta->etype[2] = ta->etype[0];
ta->etype[0] = e;
d1 = d2; d2 = d0; d0 = d;
}
/* copy all info to fragments */
tmpspot = tc->spot; *tc = *ta; tc->spot = tmpspot;
tmpspot = td->spot; *td = *ta; td->spot = tmpspot;
retval = 2;
/* fill in fragment info */
for ( i = 0 ; i < gdim ; i++ )
{ ta->x[2][i] = tc->x[0][i] = td->x[0][i] =
(float)(((db-d0)*td->x[2][i] + (d2-db)*ta->x[0][i])/(d2-d0));
tc->x[2][i] = td->x[1][i] =
(float)(((db-d1)*td->x[2][i] + (d2-db)*ta->x[1][i])/(d2-d1));
}
/* internal edges invisible */
ta->etype[1] = tc->etype[0] = tc->etype[2] = td->etype[0] = SPLITTING_EDGE;
/* set mins and maxs */
for ( i = 0 ; i < gdim ; i++ )
{ int j;
ta->mins[i] = tc->mins[i] = td->mins[i] = (float)1e30;
ta->maxs[i] = tc->maxs[i] = td->maxs[i] = (float)(-1e30);
for ( j = 0 ; j < 3 ; j++ )
{ if ( ta->x[j][i] < ta->mins[i] ) ta->mins[i] = ta->x[j][i];
if ( tc->x[j][i] < tc->mins[i] ) tc->mins[i] = tc->x[j][i];
if ( td->x[j][i] < td->mins[i] ) td->mins[i] = td->x[j][i];
if ( ta->x[j][i] > ta->maxs[i] ) ta->maxs[i] = ta->x[j][i];
if ( tc->x[j][i] > tc->maxs[i] ) tc->maxs[i] = tc->x[j][i];
if ( td->x[j][i] > td->maxs[i] ) td->maxs[i] = td->x[j][i];
}
}
/* get ta as back part */
if ( (tc->mins[2] < ta->mins[2]) && (tc->mins[2] <= td->mins[2]) )
{ struct tsort tmp; /* get ta as back part */
tmp = *ta;
*ta = *tc;
*tc = tmp;
tmpspot = ta->spot; ta->spot = tc->spot; tc->spot = tmpspot;
}
else if ( td->mins[2] < ta->mins[2] )
{ struct tsort tmp; /* get ta as back part */
tmp = *ta;
*ta = *td;
*td = tmp;
tmpspot = ta->spot; ta->spot = td->spot; td->spot = tmpspot;
}
/* find_bbox(tc); */
/* find_bbox(td); */
if ( setquadcode(tc) == INTHEBOX )
{ qdepth_insert(tc);
if ( setquadcode(td) == INTHEBOX )
qdepth_insert(td);
else { retval--; td->flag = 0; td->next = (struct tsort *)0xFF; }
}
else
{ /* discard tc */
tmpspot = tc->spot;
*tc = *td;
tc->spot = tmpspot;
td->flag = 0; td->next = (struct tsort *)0xAA;
retval--;
if ( setquadcode(tc) == INTHEBOX )
qdepth_insert(tc);
else { retval--; tc->flag = 0; tc->next = (struct tsort *)0xEE; }
}
return retval;
}
/*********************************************************************
*
* function: separating_plane()
*
* purpose: See if two facets have a separating plane in 3D.
* Meant to be called when known the facets overlap in 2D.
*
* returns FIRST_BACK, SECOND_BACK, or ASPLITTINGB | BSPLITTINGA
*/
int separating_plane(ta,tb,depth)
struct tsort *ta,*tb;
int depth; /* to limit recursion to depth 2 */
{ int i,j;
int na,nb; /* vertices on respective elements */
int nna; /* number of vertex pairs to check on ta */
float *a[3],*b[3];
int retval;
REAL da,db,d;
int n,k,bnear=0,beq=0,bfar=0,anear=0,afar=0,aeq=0;
sep_plane_calls++; /* for verbose statistics */
/* see where tb is with respect to ta plane */
if ( (ta->flag & 0xF) == FACET )
{ da = dotf(ta->normal,ta->x[0],gdim);
n = ((tb->flag & 0xF) == FACET) ? 3 : 2;
for ( k = 0 ; k < n ; k++ )
{ d = dotf(ta->normal,tb->x[k],gdim);
if ( d < da - 0.0001 ) { bnear++; continue; }
if ( d < da + 0.0001 ) { beq++; continue; }
bfar++;
}
if ( beq == n )
return ((tb->flag&0xF)==EDGE)?FIRST_BACK:DISJOINT; /* in same plane */
if ( bfar == 0 ) return FIRST_BACK;
}
/* see where ta is with respect to tb plane */
if ( (tb->flag & 0xF) == FACET )
{ db = dotf(tb->normal,tb->x[0],gdim);
n = ((ta->flag & 0xF) == FACET) ? 3 : 2;
for ( k = 0 ; k < n ; k++ )
{ d = dotf(tb->normal,ta->x[k],gdim);
if ( d < db - 0.0001 ) { anear++; continue; }
if ( d < db + 0.0001 ) { aeq++; continue; }
afar++;
}
if ( aeq == n )
return ((ta->flag&0xF)==EDGE)?SECOND_BACK:DISJOINT; /* same plane */
if ( anear == 0 ) return FIRST_BACK;
}
na = (ta->flag & 0xF) == FACET ? 3 : 2;
nna = (ta->flag & 0xF) == FACET ? 3 : 1;
nb = (tb->flag & 0xF) == FACET ? 3 : 2;
for ( i = 0 ; i < nna ; i++ )
for ( j = 0 ; j < nb ; j++ )
{ REAL c[3],d; /* coefficients for plane */
REAL da[3],db[3],minarea,s[3],length,dar[3],dbr[3];
int ii,jj,jjj;
for ( ii = 0 ; ii < na ; ii++ )
a[ii] = ta->x[(i+ii)%na];
for ( jj = 0 ; jj < nb ; jj++ )
b[jj] = tb->x[(j+jj)%nb];
for ( ii = 0 ; ii < 3 ; ii++ ) s[ii] = a[1][ii]-a[0][ii];
length = sqrt(s[0]*s[0]+s[1]*s[1]+s[2]*s[2]);
minarea = 1e-4*length;
c[0] = s[1]*(b[0][2]-a[0][2]) - s[2]*(b[0][1]-a[0][1]);
c[1] = s[2]*(b[0][0]-a[0][0]) - s[0]*(b[0][2]-a[0][2]);
c[2] = s[0]*(b[0][1]-a[0][1]) - s[1]*(b[0][0]-a[0][0]);
if ( c[0]*c[0] + c[1]*c[1] + c[2]*c[2] <= minarea*minarea )
continue; /* degenerate */
d = c[0]*a[0][0] + c[1]*a[0][1] + c[2]*a[0][2];
for ( ii = 2 ; ii < na ; ii++ )
{ dar[ii] = c[0]*a[ii][0] + c[1]*a[ii][1] +c[2]*a[ii][2] - d;
da[ii] = ( dar[ii] < -minarea ? -1.0 : ( dar[ii] > minarea ? 1.0 : 0.0));
}
for ( jj = 1 ; jj < nb ; jj++ )
{ dbr[jj] = c[0]*b[jj][0] + c[1]*b[jj][1] +c[2]*b[jj][2] - d;
db[jj] = ( dbr[jj] < -minarea ? -1.0 : ( dbr[jj] > minarea ? 1.0 : 0.0));
}
/* test opposite sidedness */
for ( jj = 1 ; jj < nb ; jj++ )
for ( jjj = jj+1 ; jjj < nb ; jjj++ )
if ( db[jj]*db[jjj] < 0.0 ) goto keeptrying;
for ( ii = 2 ; ii < na ; ii++ )
for ( jj = 1 ; jj < nb ; jj++ )
if ( da[ii]*db[jj] > 0.0 ) goto keeptrying;
/* have separating plane */
{ REAL asum,bsum;
/* decide which is in front */
for ( ii = 2, asum = 0.0 ; ii < na ; ii++ ) asum += c[2]*da[ii];
for ( jj = 1, bsum = 0.0 ; jj < nb ; jj++ ) bsum += c[2]*db[jj];
if ( asum > 0.0 || bsum < 0.0 ) return SECOND_BACK;
else return FIRST_BACK;
}
keeptrying: ;
}
/* might have case of separating plane having two vertices on tb */
if ( depth == 2 )
return ASPLITTINGB|BSPLITTINGA;
retval = separating_plane(tb,ta,2);
if ( retval == FIRST_BACK )
return SECOND_BACK;
if ( retval == SECOND_BACK )
return FIRST_BACK;
return retval;
}
/*********************************************************************
*
* function: separating_line()
*
* purpose: See if two elements have a separating line in 2D.
* To be called after bounding box tests.
* Includes small tolerance.
*
* returns DISJOINT or NOTKNOWN
*/
int separating_line(ta,tb)
struct tsort *ta,*tb;
{ int i;
int same = 0;
int na,nb; /* vertices on respective elements */
int nna,nnb; /* number of lines to try */
int apos,aneg,bpos,bneg;
float *a[3],*b[3];
REAL width; /* thickness of separating line */
sep_line_calls++; /* for verbose statistics */
/* get edge first, if any */
if ( ((ta->flag & 0xF) == FACET) && ((tb->flag & 0xF) == EDGE ) )
{ struct tsort *tmp = ta; ta = tb; tb = tmp; }
/* want to prevent overlap of facet with thick edge; not going
to worry about edge-edge overlap, since that too weird. */
if ( ((ta->flag & 0xF) == EDGE) && ((tb->flag & 0xF) == FACET ) )
{
width = ta->width/2; /* actually need half-width */
}
else width = -1e-5; /* allow slight overlap for numerical purposes */
na = (ta->flag & 0xF) == FACET ? 3 : 2;
nb = (tb->flag & 0xF) == FACET ? 3 : 2;
nna = (ta->flag & 0xF) == FACET ? 3 : 1;
nnb = (tb->flag & 0xF) == FACET ? 3 : 1;
/* Try using edges of ta */
for ( i = 0 ; i < nna ; i++ )
{ REAL cx,cy,d; /* coefficients for line */
REAL dar[3],dbr[3],minarea;
int ii,jj;
for ( ii = 0 ; ii < na ; ii++ )
a[ii] = ta->x[(i+ii)%na];
for ( jj = 0 ; jj < nb ; jj++ )
b[jj] = tb->x[jj];
cx = a[1][1] - a[0][1]; cy = a[0][0] - a[1][0];
d = cx*a[0][0] + cy*a[0][1];
minarea = width*sqrt(cx*cx + cy*cy);
if ( fabs(minarea) < 1e-20 )
{ same++; continue; /* same point */ }
apos = aneg = bpos = bneg = 0;
for ( ii = 2 ; ii < na ; ii++ )
{ dar[ii] = cx*a[ii][0] + cy*a[ii][1] - d;
if ( dar[ii] > minarea ) apos++;
if ( dar[ii] < -minarea ) aneg++;
}
for ( jj = 0 ; jj < nb ; jj++ )
{ dbr[jj] = cx*b[jj][0] + cy*b[jj][1] - d;
if ( dbr[jj] > minarea ) bpos++;
if ( dbr[jj] < -minarea ) bneg++;
}
/* test opposite sidedness */
if ( apos == (na-2) && bneg == nb ) return DISJOINT;
if ( aneg == (na-2) && bpos == nb ) return DISJOINT;
}
/* Try using edges of tb */
for ( i = 0 ; i < nnb ; i++ )
{ REAL cx,cy,d; /* coefficients for line */
REAL dar[3],dbr[3],minarea;
int ii,jj;
for ( ii = 0 ; ii < nb ; ii++ )
a[ii] = tb->x[(i+ii)%nb];
for ( jj = 0 ; jj < na ; jj++ )
b[jj] = ta->x[jj];
cx = a[1][1] - a[0][1]; cy = a[0][0] - a[1][0];
d = cx*a[0][0] + cy*a[0][1];
width = -1e-5;
minarea = width*sqrt(cx*cx + cy*cy);
if ( fabs(minarea) < 1e-20 )
{ same++; continue; /* same point */ }
apos = aneg = bpos = bneg = 0;
for ( ii = 2 ; ii < nb ; ii++ )
{ dar[ii] = cx*a[ii][0] + cy*a[ii][1] - d;
if ( dar[ii] > minarea ) apos++;
if ( dar[ii] < -minarea ) aneg++;
}
for ( jj = 0 ; jj < na ; jj++ )
{ dbr[jj] = cx*b[jj][0] + cy*b[jj][1] - d;
if ( dbr[jj] > minarea ) bpos++;
if ( dbr[jj] < -minarea ) bneg++;
}
/* test opposite sidedness */
if ( apos == (nb-2) && bneg == na ) return DISJOINT;
if ( aneg == (nb-2) && bpos == na ) return DISJOINT;
}
return NOTKNOWN;
}
/*********************************************************************
*
* function: plane_test()
*
* purpose: See if one facet or edge is in front or back of element plane.
* Suitable for Newell-Newell-Sancha algorithm.
*
* returns DISJOINT, FIRST_BACK, SECOND_BACK, ASPLITTINGB, BSPLITTINGA, or COPLANAR
* Returns FIRST_BACK if guaranteed first does not obscure any of second.
* Possibly bitwise OR of properties.
*/
int plane_test(ta,tb)
struct tsort *ta,*tb;
{
REAL da,db;
int k,n;
int afar=0,aeq=0,anear=0; /* count of ta vertices relative to tb plane */
int bfar=0,beq=0,bnear=0; /* count of tb vertices relative to ta plane */
REAL d;
int retval = NOTKNOWN;
/* if two edges */
if ( ((ta->flag & 0xF) == EDGE) && ((tb->flag & 0xF) == EDGE) )
{ REAL ab1x = tb->x[0][0] - ta->x[0][0];
REAL ab1y = tb->x[0][1] - ta->x[0][1];
REAL ab1z = tb->x[0][2] - ta->x[0][2];
REAL ab2x = tb->x[1][0] - ta->x[0][0];
REAL ab2y = tb->x[1][1] - ta->x[0][1];
REAL ab2z = tb->x[1][2] - ta->x[0][2];
REAL aax = ta->x[1][0] - ta->x[0][0];
REAL aay = ta->x[1][1] - ta->x[0][1];
REAL aaz = ta->x[1][2] - ta->x[0][2];
REAL area = ab1x*ab2y - ab1y*ab2x;
REAL vol = (ab1x*ab2y - ab1y*ab2x)*aaz + (ab1y*ab2z - ab1z*ab2y)*aax
+ (ab1z*ab2x - ab1x*ab2z)*aay;
if ( vol == 0.0 ) return COPLANAR;
if ( area == 0.0 ) return DISJOINT;
if ( area*vol > 0 ) return SECOND_BACK;
return FIRST_BACK;
}
/* see where tb is with respect to ta plane */
da = dotf(ta->normal,ta->x[0],gdim);
n = ((tb->flag & 0xF) == FACET) ? 3 : 2;
for ( k = 0 ; k < n ; k++ )
{
d = dotf(ta->normal,tb->x[k],gdim);
if ( d < da - 0.0001 ) { bnear++; continue; }
if ( d < da + 0.0001 ) { beq++; continue; }
bfar++;
}
if ( beq == n ) return COPLANAR; /* both in same plane */
if ( bfar == 0 ) return FIRST_BACK;
if ( bnear > 0 )
{ if ( (ta->flag & 0xF) == FACET ) retval = ASPLITTINGB; }
else retval = SECOND_BACK;
/* see where ta is with respect to tb plane */
db = dotf(tb->normal,tb->x[0],gdim);
n = ((ta->flag & 0xF) == FACET) ? 3 : 2;
for ( k = 0 ; k < n ; k++ )
{
d = dotf(tb->normal,ta->x[k],gdim);
if ( d < db - 0.0001 ) { anear++; continue; }
if ( d < db + 0.0001 ) { aeq++; continue; }
afar++;
}
if ( aeq == n ) return COPLANAR; /* both in same plane */
if ( anear == 0 ) return FIRST_BACK;
if ( afar > 0 )
{ if ( (tb->flag & 0xf) == FACET ) retval |= BSPLITTINGA; }
else retval |= SECOND_BACK;
/* might still not have properly detected order, so try this */
/*
if ( !(retval & (FIRST_BACK|SECOND_BACK)) )
retval = separating_plane(ta,tb,0);
*/
return retval;
} /* end plane_test() */
/************************************************************************
************************************************************************
Visibility testing. Takes output of depth sort and deletes hidden
elements. Uses sweep line (at random angle) to track topology.
Much like Stuart Sechrest and Donald P. Greenberg, A Visible Polygon
Reconstruction Algorithm, ACM Transactions on Graphics, vol 1, no 1,
Jan 1982, pp 25-42.
General strategy remarks:
The image is broken down into individual polygon edges. Each edge is
"above" or "below" a polygon. For now, each polygon is just a facet,
but this could change if thick edges were added in the form of rectangles.
The algorithm proceeds by moving a sweep line across the image, keeping
track of "active edges" that intersect the sweep line. The active edge
list is altered at "events": edge starts, edge ends, and edge crossings.
The sweep line is tilted at an arbitrary angle to prevent degenerate
vertices, except vertices coincident in projection. Pre-ordered event
lists are kept for edge starts and ends, and a heap for upcoming
crossings.
Attached to each active edge is a list of layers of facets in the area
immediately above it.
*************************************************************************/
int visdebuglevel;
#define VIS_TIMING 1
#define VIS_LAYERCHECK 2
#define VIS_EVENTDUMP 3
struct vis_conedge;
struct vis_vertex;
/* Heap for ordering upcoming events. */
int vis_heap_count; /* heap spots used */
int vis_heap_max; /* heap spots allocated */
struct vis_event *vis_heap;
void vis_insert_heap ARGS((struct vis_event *));
void vis_delete_heap ARGS((int));
void find_next_event ARGS((struct vis_conedge *));
void find_next_event2 ARGS(( struct vis_conedge *, struct vis_conedge *));
void vis_crossing ARGS((struct vis_conedge *,struct vis_conedge *));
int vecount; /* number of edges in edge list */
int vis_crossing_count; /* just for info */
int add_layer ARGS((struct vis_conedge *, struct tsort *));
int delete_layer ARGS((struct vis_conedge *, struct tsort *));
void check_layers ARGS(( struct vis_conedge *, REAL , REAL));
int vvcomp ARGS(( struct vis_vertex *, struct vis_vertex *));
REAL activate_edge ARGS(( struct vis_conedge *));
void check_deactivate ARGS(( struct vis_conedge *));
/* Edge list */
#define MAXLAYERS 20
struct vis_rawedge { struct vis_vertex *v[2]; /* endpoints */
struct tsort *t; /* facet it borders */
struct vis_conedge *conedge;
int flags; /* see below */
};
struct vis_rawedge *vis_rawedges;
struct vis_rawedge **rawplist; /* pointers for sorting */
int vecomp ARGS((struct vis_rawedge **, struct vis_rawedge **));
/* vis_rawedge flag bits */
#define V_FACET_BOTTOM 1
#define V_FACET_TOP 2
#define V_FACET_LEFT 4
#define V_FACET_RIGHT 8
#define V_LAYER_CHECK 0x10
/* Consolidated vertices */
struct vis_vertex { REAL x[2]; /* u, v */
struct vis_vertex **fixup[2]; /* pre-cons reverse pointer */
};
struct vis_vertex *vis_vertices;
int vis_vertex_max;
int vis_vertex_count;
/* Consolidated edges */
struct vis_conedge {
struct vis_vertex *v[2]; /* endpoints */
REAL m; /* line slope */
int rawstart; /* associated raw edge start */
int rawend; /* last associated raw edge */
int use_count; /* times in use as boundary */
struct vis_conedge *prev_active; /* active list pointer */
struct vis_conedge *next_active; /* active list pointer */
int flags; /* see below */
int layers; /* number of layers above edge */
struct tsort **layer; /* facets "above" edge */
int maxlayers; /* allocated space */
int seqno; /* sequence number, for debugging */
};
struct vis_conedge *vis_conedges;
int vis_conedge_max;
int vis_conedge_count;
/* Crossing event */
struct vis_event { REAL time; /* sweep time of event */
int type;
struct vis_conedge *e1;
struct vis_conedge *e2;
struct tsort *t;
};
int vis_event_comp ARGS((struct vis_event *, struct vis_event *));
/* Event types, ordered in way wanted in sorting */
#define V_FACET_END 1
#define V_FACET_TOPMIDDLE 2
#define V_FACET_BOTTOMMIDDLE 3
#define V_FACET_START 4
#define V_EDGE_CROSSING 5
int wrong_middles; /* for some debugging */
/* Margin to shorten edge ends, so don't get spurious crossings */
REAL veps = 1e-14;
/* Active edge list */
struct vis_conedge *active_edge_first;
struct vis_conedge sentinel;
struct vis_vertex sentinelv[4]; /* for sentinel endpoints */
/* List of edges to check for top layer */
struct vis_conedge **check_list;
int check_list_count;
int check_list_max;
void check_visible ARGS((REAL));
/* random tilt coefficients for sweep line */
REAL va = 0.8432848996472634;
REAL vb = 0.5869487870825054;
REAL sweep_u; /* current sweep position */
struct vis_event *facet_events;
int f_event_count;
int facet_start_event ARGS((struct vis_event *));
int facet_middle_event ARGS((struct vis_event *));
int facet_end_event ARGS((struct vis_event *));
/* For brute force verification */
int brute_force_flag = 1;
void brute_force_times ARGS((void));
int brutecount; /* number of brute force times */
struct brute { REAL time;
struct vis_conedge *e1,*e2;
int type;
} *brute_times;
void brute_section ARGS((REAL));
void brute_visible ARGS((REAL));
int maxbrute;
struct brute_cut { REAL v; /* height */
struct vis_edge *e;
} *brute_cuts;
int brute_cut_count;
#ifdef PROFILING_ENABLED
/* Profiling cycle counters */
__int32 visibility_stage_elapsed_time[2];
__int32 visibility_end_elapsed_time[2];
__int32 visibility_end1_elapsed_time[2];
__int32 visibility_end2_elapsed_time[2];
__int32 visibility_end3_elapsed_time[2];
__int32 visibility_end4_elapsed_time[2];
__int32 visibility_end5_elapsed_time[2];
__int32 vis_insert_heap_elapsed_time[2];
__int32 vis_delete_heap_elapsed_time[2];
__int32 vis_crossing_elapsed_time[2];
__int32 facet_start_event_elapsed_time[2];
__int32 facet_middle_event_elapsed_time[2];
__int32 facet_end_event_elapsed_time[2];
__int32 add_layer_elapsed_time[2];
__int32 delete_layer_elapsed_time[2];
__int32 check_visible_elapsed_time[2];
__int32 find_next_event_elapsed_time[2];
__int32 all_visibility_elapsed_time[2];
__int32 activate_edge_elapsed_time[2];
__int32 check_deactivate_elapsed_time[2];
#endif
/************************************************************************
*
* function: visibility_stage()
*
* purpose: Adds element to list for visibility testing.
* Enabled by visibility_test toggle.
*
*/
void visibility_stage(t)
struct tsort *t;
{
PROF_START(all_visibility)
PROF_START(visibility_stage)
if ( !visibility_test )
{ if ( (t->flag & 0xF) == FACET )
(*display_facet)(t);
else (*display_edge)(t);
return;
}
/* accumulate */
if ( vis_list == NULL )
{ vis_max = maxcount;
vis_list = (struct tsort *)temp_calloc(vis_max,sizeof(struct tsort));
}
else if ( vis_count >= vis_max - 1 )
{ vis_list = (struct tsort *)temp_realloc((char*)vis_list,
2*vis_max*sizeof(struct tsort));
vis_max *= 2;
}
vis_list[vis_count++] = *t;
PROF_FINISH(visibility_stage)
PROF_FINISH(all_visibility)
}
/*
FOR DEBUGGING
*/
void active_list_check ARGS((void));
void active_list_check()
{ struct vis_conedge *e;
for ( e = active_edge_first ; e != &sentinel ; e = e->next_active )
{ if ( e->next_active->prev_active != e )
kb_error(2418,"Visibility edge active list bad.\n",RECOVERABLE);
}
}
/************************************************************************
*
* function: vvcomp()
*
* purpose: comparison of vertices, for consolidation
*
*/
int vvcomp(a,b)
struct vis_vertex *a,*b;
{
if ( a->x[0] < b->x[0] ) return -1;
if ( a->x[0] > b->x[0] ) return 1;
if ( a->x[1] < b->x[1] ) return -1;
if ( a->x[1] > b->x[1] ) return 1;
return 0;
}
/************************************************************************
*
* function: vecomp()
*
* purpose: comparison of raw edges, for consolidation
*
*/
int vecomp(a,b)
struct vis_rawedge **a,**b;
{
if ( a[0]->v[0] < b[0]->v[0] ) return -1;
if ( a[0]->v[0] > b[0]->v[0] ) return 1;
if ( a[0]->v[1] < b[0]->v[1] ) return -1;
if ( a[0]->v[1] > b[0]->v[1] ) return 1;
return 0;
}
/************************************************************************
*
* function: visibility_end()
*
* purpose: Run visibility algorithm after accumulation of data.
*
*/
int debug_seq = 0; /* for debugging */
void visibility_end()
{ int k,i,ii,iii,j;
struct tsort *t;
struct vis_rawedge *ve;
struct vis_conedge *vc;
struct vis_vertex *vv;
REAL next_u;
struct vis_event *f_ev;
int facet_event_spot;
int vis_display_count;
int tops,bottoms,lefts,rights;
debug_seq = 0;
PROF_START(all_visibility)
PROF_START(visibility_end)
PROF_START(visibility_end1)
/* List of edges to check top facet for */
check_list_max = 1000;
check_list = (struct vis_conedge **)temp_calloc(check_list_max,
sizeof(struct vis_conedge *));
check_list_count = 0;
/* Sorted list of facet starts, middle vertices, and ends */
facet_events = (struct vis_event *)temp_calloc(3*vis_count,
sizeof(struct vis_event));
f_event_count = 0;
f_ev = facet_events;
/* Populate raw edge and vertex lists */
vis_vertex_max = 3*vis_count;
vis_vertices = (struct vis_vertex *)temp_calloc(vis_vertex_max,
sizeof(struct vis_vertex));
vv = vis_vertices;
vis_vertex_count = 0;
vis_rawedges = (struct vis_rawedge *)temp_calloc(3*vis_count,
sizeof(struct vis_rawedge));
ve = vis_rawedges;
vecount = 0;
for ( k = 0, t = vis_list ; k < vis_count ; k++,t++ )
{ if ( (t->flag & 0xF) == FACET )
{
REAL minu = 1e30, maxu = -1e30;
if ( t->color == CLEAR )
{ t->flag |= VISIBLE; continue; } /* kludge for now */
/* rotate coordinates */
for ( i = 0 ; i < FACET_VERTS ; i++ )
{ vv[i].x[0] = va*t->x[i][0] + vb*t->x[i][1];
if ( vv[i].x[0] < minu ) minu = vv[i].x[0];
if ( vv[i].x[0] > maxu ) maxu = vv[i].x[0];
vv[i].x[1] = -vb*t->x[i][0] + va*t->x[i][1];
}
/* now, the edges */
tops = 0; bottoms = 0; lefts = 0; rights = 0;
for ( i = 0 ; i < FACET_VERTS ; i++ )
{ REAL area;
ii = (i+1 >= FACET_VERTS) ? 0 : i+1;
if ( vv[i].x[0] <= vv[ii].x[0] ) /* leftmost vertex first */
{ ve->v[0] = vv+i;
ve->v[1] = vv+ii;
vv[i].fixup[0] = &ve->v[0]; /* so can adjust edges after sorting vertices */
vv[ii].fixup[1] = &ve->v[1];
} else
{ ve->v[0] = vv+ii;
ve->v[1] = vv+i;
vv[i].fixup[0] = &ve->v[1]; /* so can adjust edges after sorting vertices */
vv[ii].fixup[1] = &ve->v[0];
}
iii = (ii+1 >= FACET_VERTS) ? 0 : ii+1; /* third vertex */
area = (ve->v[1]->x[0]-ve->v[0]->x[0])*(vv[iii].x[1]-ve->v[0]->x[1])
-(vv[iii].x[0]-ve->v[0]->x[0])*(ve->v[1]->x[1]-ve->v[0]->x[1]);
if ( fabs(area) < 1e-14 ) break;
if ( area > 0 )
{ ve->flags |= V_FACET_BOTTOM; bottoms++; }
else { ve->flags |= V_FACET_TOP; tops++; }
if ( ve->v[0]->x[0] == minu )
{ ve->flags |= V_FACET_LEFT; lefts++; }
if ( ve->v[1]->x[0] == maxu )
{ ve->flags |= V_FACET_RIGHT; rights++; }
ve->t = t;
ve++; vecount++;
}
/* check we successfully found things, and skip edge-on facets */
if ( (tops==0) || (bottoms==0) || (lefts!=2) || (rights!=2) )
continue;
/* facet start event */
f_ev->type = V_FACET_START;
f_ev->time = minu;
f_ev->t = t;
for ( i = -FACET_EDGES ; i < 0 ; i++ )
{ if ( ve[i].flags & V_FACET_LEFT )
{ if ( ve[i].flags & V_FACET_BOTTOM )
f_ev->e1 = (struct vis_conedge*)(ve + i);
else f_ev->e2 = (struct vis_conedge*)(ve + i);
}
}
if ( !f_ev->e1 || !f_ev->e2 )
{ f_ev->e1 = f_ev->e2 = NULL; continue; } /* skip edge-on */
f_ev++; f_event_count++;
/* facet middle event */
f_ev->t = t;
for ( i = -FACET_EDGES ; i < 0 ; i++ )
{ if ( ve[i].flags & V_FACET_LEFT )
{ if ( !(ve[i].flags & V_FACET_RIGHT) )
{ f_ev->e1 = (struct vis_conedge*)(ve + i);
f_ev->time = ve[i].v[1]->x[0];
}
}
if ( ve[i].flags & V_FACET_RIGHT )
{ if ( !(ve[i].flags & V_FACET_LEFT) )
f_ev->e2 = (struct vis_conedge*)(ve + i);
}
}
if ( !f_ev->e1 || !f_ev->e2 ) /* skip edge-on */
{ f_ev->e1 = f_ev->e2 = NULL; f_ev--; f_event_count--; continue; }
if ( ((struct vis_rawedge *)f_ev->e1)->flags & V_FACET_BOTTOM )
f_ev->type = V_FACET_BOTTOMMIDDLE;
else f_ev->type = V_FACET_TOPMIDDLE;
f_ev++; f_event_count++;
/* facet end event */
f_ev->type = V_FACET_END;
f_ev->time = maxu;
f_ev->t = t;
for ( i = -FACET_EDGES ; i < 0 ; i++ )
{ if ( ve[i].flags & V_FACET_RIGHT )
{ if ( ve[i].flags & V_FACET_BOTTOM )
f_ev->e1 = (struct vis_conedge*)(ve + i);
else f_ev->e2 = (struct vis_conedge*)(ve + i);
}
}
if ( !f_ev->e1 || !f_ev->e2 ) /* skip edge-on */
{ f_ev->e1 = f_ev->e2 = NULL; f_ev-=2; f_event_count-=2; continue; }
f_ev++; f_event_count++;
vv += FACET_VERTS; vis_vertex_count += FACET_VERTS;
}
else /* lone edge */
{
/* for now, make all lone edges visible */
t->flag |= VISIBLE;
}
}
PROF_FINISH(visibility_end1)
if ( f_event_count == 0 )
goto draw_visible;
PROF_START(visibility_end2)
/* Consolidation of vertices and edges */
/* First, consolidation of vertices */
qsort(vis_vertices,vis_vertex_count,sizeof(struct vis_vertex),FCAST vvcomp);
for ( i = -1, j = 0 ; j < vis_vertex_count ; j++ )
{ int m;
if ( (i < 0) || (vvcomp(vis_vertices+i,vis_vertices+j) != 0) )
{ vis_vertices[++i] = vis_vertices[j];
}
/* use reverse pointers to fix up edges */
for ( m = 0 ; m < 2 ; m++ )
*(vis_vertices[j].fixup[m]) = vis_vertices+i;
}
vis_vertex_count = i+1;
PROF_FINISH(visibility_end2)
/* Next, consolidation of edges. Use intermediate list of pointers,
since events point to raw edges.
*/
PROF_START(visibility_end3)
rawplist = (struct vis_rawedge **)temp_calloc(vecount,
sizeof(struct vis_rawedge *));
for ( i = 0 ; i < vecount ; i++ ) rawplist[i] = vis_rawedges+i;
qsort(rawplist,vecount,sizeof(struct vis_rawedge*),FCAST vecomp);
vis_conedge_max = vecount;
vis_conedges = (struct vis_conedge *) temp_calloc(vis_conedge_max,
sizeof(struct vis_conedge) );
vis_conedges[0].v[0] = rawplist[0]->v[0];
vis_conedges[0].v[1] = rawplist[0]->v[1];
vis_conedges[0].rawstart = 0;
vis_conedges[0].rawend = 0;
rawplist[0]->conedge = vis_conedges;
for ( i = 0, j = 1 ; j < vecount ; j++ )
{ if ( (vis_conedges[i].v[0] != rawplist[j]->v[0]) ||
(vis_conedges[i].v[1] != rawplist[j]->v[1]) )
{ i++;
vis_conedges[i].v[0] = rawplist[j]->v[0];
vis_conedges[i].v[1] = rawplist[j]->v[1];
vis_conedges[i].rawstart = j;
vis_conedges[i].rawend = j;
}
else
vis_conedges[i].rawend++;
rawplist[j]->conedge = vis_conedges+i;
}
i++;
vis_conedges = (struct vis_conedge*)temp_realloc((char*)vis_conedges,
i*sizeof(struct vis_conedge));
vis_conedge_max = vis_conedge_count = i;
PROF_FINISH(visibility_end3)
PROF_START(visibility_end4)
/* Initialize line coefficients */
for ( i = 0, vc = vis_conedges; i < vis_conedge_count; i++, vc++ )
{ REAL du = vc->v[1]->x[0] - vc->v[0]->x[0];
REAL dv = vc->v[1]->x[1] - vc->v[0]->x[1];
vc->m = dv/du;
}
/* change facet events over to consolidated edges */
for ( i = 0 ; i < f_event_count ; i++ )
{ facet_events[i].e1 = ((struct vis_rawedge*)(facet_events[i].e1))->conedge;
facet_events[i].e2 = ((struct vis_rawedge*)(facet_events[i].e2))->conedge;
}
PROF_FINISH(visibility_end4)
/* and for later use */
brute_cuts=(struct brute_cut *)temp_calloc(vecount,sizeof(struct brute_cut));
#ifdef BRUTE
/* do brute-force list of all event times */
brute_force_times();
for ( i = 0 ; i < brutecount-1 ; i++ )
{ if ( brute_times[i+1].time-brute_times[i].time > 1e-8 )
brute_visible((brute_times[i].time+brute_times[i+1].time)/2);
}
#endif
#define FINESSE
#ifdef FINESSE
/* sort facet event list */
qsort((char*)facet_events,f_event_count,sizeof(struct vis_event),
FCAST vis_event_comp);
/* Initialize crossing event heap with sentinel */
vis_heap_max = vecount > 100 ? vecount : 100;
vis_heap = (struct vis_event *)temp_calloc(vis_heap_max,
sizeof(struct vis_event));
vis_heap[0].time = 1e30;
vis_heap_count = 1;
vis_crossing_count = 0;
/* Initialize active list */
sentinel.v[0] = sentinelv;
sentinel.v[1] = sentinelv+1;
sentinelv[0].x[0] = -1e20;
sentinelv[0].x[1] = 1e20;
sentinelv[1].x[0] = 1e20;
sentinelv[1].x[1] = 1e20;
sentinel.m = 0;
sentinel.prev_active = NULL;
sentinel.next_active = NULL;
active_edge_first = &sentinel;
PROF_START(visibility_end5)
/* Sweep */
facet_event_spot = 0;
while ( facet_event_spot < f_event_count )
{ struct vis_event *fe = facet_events + facet_event_spot;
int retval; /* return code from event handlers; < 0 for error */
/* print current active list and event heap */
if ( visdebuglevel >= VIS_EVENTDUMP )
{ struct vis_conedge *es;
if ( active_edge_first->prev_active != NULL )
printf("(%d<-) ",active_edge_first->prev_active-vis_conedges);
for ( es = active_edge_first ; es != &sentinel ; es = es->next_active )
{ if ( es->next_active->prev_active != es )
printf("(%d<-) ",es->next_active->prev_active-vis_conedges);
printf("%d ",es-vis_conedges);
}
for ( i = 0 ; i < vis_heap_count ; i++ )
if ( vis_heap[i].time > 1e20 ) printf("(sentinel) ");
else
printf("(%d %d %f)",vis_heap[i].e1-vis_conedges,vis_heap[i].e2-vis_conedges,
vis_heap[i].time);
printf("\n");
} /* end debug */
/* find which is next event and process */
if ( (vis_heap_count <= 0) || (fe->time < vis_heap[0].time) )
{ /* do facet event */
next_u = fe->time;
PROF_FINISH(visibility_end)
if ( (next_u - sweep_u) > 1e-10 )
check_visible((next_u+sweep_u)/2);
sweep_u = next_u;
switch ( fe->type )
{ case V_FACET_START:
retval = facet_start_event(fe);
if ( retval < 0 )
goto bail_out;
break;
case V_FACET_TOPMIDDLE:
retval = facet_middle_event(fe);
if ( retval < 0 )
goto bail_out;
break;
case V_FACET_BOTTOMMIDDLE:
retval = facet_middle_event(fe);
if ( retval < 0 )
goto bail_out;
break;
case V_FACET_END:
retval = facet_end_event(fe);
if ( retval < 0 )
goto bail_out;
break;
}
PROF_START(visibility_end)
facet_event_spot++;
continue;
}
else /* do crossing event */
{ struct vis_conedge *e1,*e2;
next_u = vis_heap[0].time;
PROF_FINISH(visibility_end)
if ( (next_u - sweep_u) > 1e-10 )
check_visible((next_u+sweep_u)/2);
e1 = vis_heap[0].e1; e2 = vis_heap[0].e2;
vis_delete_heap(0);
if ( visdebuglevel >= VIS_EVENTDUMP )
printf("crossing %d %d at %20.15f\n",e1-vis_conedges,e2-vis_conedges,(double)next_u);
sweep_u = next_u;
vis_crossing(e1,e2);
PROF_START(visibility_end)
continue;
}
}
#endif
goto draw_visible;
bail_out: /* error handling: mark all as visible */
erroutstring("Abandoning visibility test and drawing all facets.\n");
for ( k = 0, t = vis_list, vis_display_count = 0 ; k < vis_count ; k++,t++ )
t->flag |= VISIBLE;
draw_visible:
PROF_FINISH(visibility_end5)
PROF_FINISH(visibility_end)
PROF_FINISH(all_visibility)
/* Display elements marked visible */
for ( k = 0, t = vis_list, vis_display_count = 0 ; k < vis_count ; k++,t++ )
if ( t->flag & VISIBLE )
{ if ( (t->flag & 0xF) == FACET )
(*display_facet)(t);
else (*display_edge)(t);
vis_display_count++;
}
temp_free((char*)vis_heap);
temp_free((char*)vis_conedges);
temp_free((char*)vis_rawedges);
temp_free((char*)vis_vertices);
temp_free((char*)check_list);
temp_free((char*)rawplist);
temp_free((char*)vis_list);
temp_free((char*)facet_events);
temp_free((char*)brute_cuts);
if (visdebuglevel >= VIS_TIMING)
{
fprintf(stderr,"Visible: %d facets out of %d\n",vis_display_count,vis_count);
fprintf(stderr,"Crossing count: %d\n",vis_crossing_count);
fprintf(stderr,"Wrong middles: %d\n",wrong_middles); wrong_middles = 0;
#ifdef MSC
/* print out profile times, only for Visual Studio */
printf("CPU clock cycles in various visibility routines:\n");
PROF_PRINT(all_visibility)
PROF_PRINT(visibility_stage)
PROF_PRINT(visibility_end)
PROF_PRINT(visibility_end1)
PROF_PRINT(visibility_end2)
PROF_PRINT(visibility_end3)
PROF_PRINT(visibility_end4)
PROF_PRINT(visibility_end5)
PROF_PRINT(check_visible)
PROF_PRINT(vis_crossing)
PROF_PRINT(facet_start_event)
PROF_PRINT(facet_middle_event)
PROF_PRINT(facet_end_event)
PROF_PRINT(vis_insert_heap)
PROF_PRINT(vis_delete_heap)
PROF_PRINT(find_next_event)
PROF_PRINT(add_layer)
PROF_PRINT(delete_layer)
PROF_PRINT(activate_edge)
PROF_PRINT(check_deactivate)
#endif
}
}
/************************************************************************
*
* function: vis_event_comp()
*
* purpose: compare times of two events. Sorts on time, then type,
* then average slope, then edges.
*/
int vis_event_comp(a,b)
struct vis_event *a, *b;
{ REAL ma,mb;
if ( a->time < b->time ) return -1;
if ( a->time > b->time ) return 1;
if ( a->type < b->type ) return -1;
if ( a->type > b->type ) return 1;
ma = (a->e1->m+a->e2->m);
mb = (b->e1->m+b->e2->m);
if ( ma < mb ) return -1;
if ( ma > mb ) return 1;
if ( a->e1 < b->e1 ) return -1;
if ( a->e1 > b->e1 ) return 1;
if ( a->e2 < b->e2 ) return -1;
if ( a->e2 > b->e2 ) return 1;
return 0;
}
/************************************************************************
*
* function: vis_insert_heap()
*
* purpose: Add edge event to heap list. Not detecting duplicates;
* leaving that to validity test when crossing is handled.
*
*/
void vis_insert_heap(e)
struct vis_event *e;
{ int k,kk;
int result;
PROF_START(vis_insert_heap)
if ( vis_heap_count >= vis_heap_max-1 )
{ vis_heap = (struct vis_event *)kb_realloc((char*)vis_heap,
2*vis_heap_max*sizeof(struct vis_event));
vis_heap_max *= 2;
}
for ( k = vis_heap_count ; k > 0 ; k = kk )
{
kk = (k-1)/2;
result = vis_event_comp(e,&vis_heap[kk]);
if ( result < 0 )
{
vis_heap[k] = vis_heap[kk];
}
else break;
}
vis_heap[k] = *e;
vis_heap_count++;
PROF_FINISH(vis_insert_heap)
}
/***************************************************************************
*
* function: vis_delete_heap()
*
* purpose: Delete element n of heap and adjust heap.
*/
void vis_delete_heap(n)
int n;
{ int k,kk;
int result;
struct vis_event e;
PROF_START(vis_delete_heap)
if ( n == vis_heap_count-1 )
{ vis_heap_count--;
goto vis_delete_heap_exit;
}
if ( vis_heap_count == 1 )
kb_error(2421,"vis_delete_heap trying to delete sentinel.\n",RECOVERABLE);
/* replace with top event */
e = vis_heap[--vis_heap_count];
/* check direction to percolate */
result = (n==0) ? 1 : vis_event_comp(&e,vis_heap+(n-1)/2);
if ( result < 0 )
{ /* downward */
k = n;
kk = (n-1)/2;
vis_heap[k] = vis_heap[kk];
for ( k = kk ; k > 0 ; k = kk )
{ kk = (k-1)/2;
result = vis_event_comp(&e,vis_heap+kk);
if ( result < 0 )
{ vis_heap[k] = vis_heap[kk];
continue;
}
else
{ break;
}
}
vis_heap[k] = e;
goto vis_delete_heap_exit;
}
else
{ /* upward */
for ( k = n; 2*k+1 < vis_heap_count ; k = kk )
{
if ( 2*k+2 >= vis_heap_count )
{ /* only one parent */
kk = 2*k+1;
result = vis_event_comp(&e,vis_heap+kk);
if ( result > 0 )
{ vis_heap[k] = vis_heap[kk];
vis_heap[kk] = e;
goto vis_delete_heap_exit;
}
else
{ vis_heap[k] = e;
goto vis_delete_heap_exit;
}
}
else
{ /* two parents */
result = vis_event_comp(&vis_heap[2*k+1],&vis_heap[2*k+2]);
kk = (result < 0) ? 2*k+1 : 2*k+2;
result = vis_event_comp(&e,vis_heap+kk);
if ( result < 0 )
{ /* done */
vis_heap[k] = e;
goto vis_delete_heap_exit;
}
else if ( result > 0 )
{ /* keep going up */
vis_heap[k] = vis_heap[kk];
continue;
}
}
}
vis_heap[k] = e; /* in case at top of heap */
}
vis_delete_heap_exit: ;
PROF_FINISH(vis_delete_heap)
}
/****************************************************************************
*
* function: add_layer()
*
* purpose: Add a facet to the layers above an active edge.
*
* return value: 1 if added, 0 if already there.
*/
int add_layer(ee,f)
struct vis_conedge *ee;
struct tsort *f;
{ int i;
int retval;
PROF_START(add_layer)
for ( i = 0 ; i < ee->layers ; i++ )
if ( ee->layer[i] == f ) break;
if ( i == ee->maxlayers )
{ int newcount = (ee->maxlayers > 10) ? 2*ee->maxlayers : ee->maxlayers + 10;
ee->layer = (struct tsort **)temp_realloc((char*)(ee->layer),
newcount*sizeof(struct tsort*));
ee->maxlayers = newcount;
}
if ( i == ee->layers )
{ /* not already found in layer list */
ee->layer[ee->layers++] = f;
if ( visdebuglevel >= VIS_EVENTDUMP )
fprintf(stderr,"Adding facet %d to edge %d layers.\n",
f-vis_list,ee-vis_conedges);
if ( !(ee->flags & V_LAYER_CHECK) )
{
if ( check_list_count >= check_list_max )
{ check_list = (struct vis_conedge **)temp_realloc((char*)check_list,
2*check_list_max*sizeof(struct vis_conedge *));
check_list_max *= 2;
}
check_list[check_list_count++] = ee;
ee->flags |= V_LAYER_CHECK;
}
retval = 1;
}
else retval = 0;
PROF_FINISH(add_layer)
return retval;
}
/****************************************************************************
*
* function: delete_layer()
*
* purpose: Delete a facet from the layers above an active edge.
* Not keeping remaining facets in depth order.
*
* return value: 1 if found, 0 if not.
*/
int delete_layer(ee,f)
struct vis_conedge *ee;
struct tsort *f;
{ int i;
int retval = 0;
PROF_START(delete_layer)
for ( i = 0 ; i < ee->layers ; i++ )
if ( ee->layer[i] == f )
{ ee->layer[i] = ee->layer[--ee->layers];
if ( visdebuglevel >= VIS_EVENTDUMP )
fprintf(stderr,"Deleting facet %d from edge %d layers.\n",
f-vis_list,ee-vis_conedges);
if ( !(ee->flags & V_LAYER_CHECK) )
{ if ( check_list_count >= check_list_max )
{ check_list = (struct vis_conedge **)temp_realloc((char*)check_list,
2*check_list_max*sizeof(struct vis_conedge *));
check_list_max *= 2;
}
check_list[check_list_count++] = ee;
ee->flags |= V_LAYER_CHECK;
}
retval = 1;
break;
}
PROF_FINISH(delete_layer)
return retval;
}
/*************************************************************************
*
* function: find_next_event()
*
* purpose: Check for upcoming crossing event. Doesn't count crossing
* near end of edge. Need to do very robust crossing
* calculation, so not to be fooled by numerical glitches.
*
*/
void find_next_event(e)
struct vis_conedge *e;
{ struct vis_event ev;
PROF_START(find_next_event)
ev.time = 1e30;
/* Forward */
if ( (e->m > e->next_active->m ) )
{ REAL u;
u = e->v[0]->x[0] + (e->v[0]->x[1]-e->next_active->v[0]->x[1] +
e->next_active->m*(e->next_active->v[0]->x[0]-e->v[0]->x[0]))/
(e->next_active->m - e->m);
if ( (u > e->v[0]->x[0]-1e-8) && (u < ev.time) && (u < e->v[1]->x[0] - 1e-10)
&& (u < e->next_active->v[1]->x[0] - 1e-10) )
{ ev.e1 = e;
ev.e2 = e->next_active;
ev.time = u;
}
}
/* Backward */
if ( e->prev_active && (e->m < e->prev_active->m))
{ REAL u;
u = e->v[0]->x[0] + (e->v[0]->x[1]-e->prev_active->v[0]->x[1] +
e->prev_active->m*(e->prev_active->v[0]->x[0]-e->v[0]->x[0]))/
(e->prev_active->m - e->m);
if ( (u > e->v[0]->x[0]-1e-8) && (u < ev.time) && (u < e->v[1]->x[0] - 1e-10)
&& (u < e->prev_active->v[1]->x[0] - 1e-10) )
{ ev.e1 = e->prev_active;
ev.e2 = e;
ev.time = u;
}
}
PROF_FINISH(find_next_event)
if ( ev.time < 1e20 )
{
if ( visdebuglevel >= VIS_EVENTDUMP )
printf("next crossing %d %d at %20.15f\n",
ev.e1-vis_conedges,ev.e2-vis_conedges, (double)ev.time);
vis_insert_heap(&ev);
}
}
/*************************************************************************
*
* function: find_next_event2()
*
* purpose: Check for upcoming crossing event between two given edges.
* Doesn't count crossing
* near end of edge. Need to do very robust crossing
* calculation, so not to be fooled by numerical glitches.
*
*/
void find_next_event2(e,ee)
struct vis_conedge *e;
struct vis_conedge *ee;
{ struct vis_event ev;
if ( !e || !ee ) return;
ev.time = 1e30;
/* Forward */
if ( (e->m > ee->m ) )
{ REAL u;
u = e->v[0]->x[0] + (e->v[0]->x[1]-e->next_active->v[0]->x[1] +
e->next_active->m*(e->next_active->v[0]->x[0]-e->v[0]->x[0]))/
(e->next_active->m - e->m);
if ( (u > e->v[0]->x[0]-1e-8) && (u < ev.time) && (u < e->v[1]->x[0] - 1e-10)
&& (u < e->next_active->v[1]->x[0] - 1e-10) )
{ ev.e1 = e;
ev.e2 = e->next_active;
ev.time = u;
}
}
if ( ev.time < 1e20 )
{
if ( visdebuglevel >= VIS_EVENTDUMP )
printf("next crossing %d %d at %20.15f\n",
ev.e1-vis_conedges,ev.e2-vis_conedges, (double)ev.time);
vis_insert_heap(&ev);
}
}
#ifdef XXXXXX
/* for debugging */
/**************************************************************************
*
* function: dump_vislist()
*
* purpose: dump edge list in case of error.
*/
void dump_vislist()
{ struct vis_conedge *e;
REAL v;
int i;
fprintf(stderr,"Visibility edge list debug dump at u = %18.15f; debug_seq %d\n",
sweep_u,debug_seq);
for ( e = active_edge_first ; e != &sentinel ; e = e->next_active )
{ if ( e == NULL ) { fprintf(stderr,"NULL next_active.\n"); break; }
v = e->m*(sweep_u-e->v[0]->x[0]) + e->v[0]->x[1];
fprintf(stderr,"%3d %5d v: %18.15f layers:",e->seqno,e-vis_conedges,v);
for ( i = 0 ; i < e->layers ; i++ )
fprintf(stderr," %3d",ordinal(e->layer[i]->f_id)+1);
fprintf(stderr,"\n");
}
fprintf(stderr,"\n");
}
void check_vislist() /* for v in ascending sequence */
{ struct vis_conedge *e;
REAL v,prev = -1e30;
for ( e = active_edge_first ; e != &sentinel ; e = e->next_active )
{ if ( e == NULL ) { fprintf(stderr,"NULL next_active.\n"); break; }
v = e->m*(sweep_u-e->v[0]->x[0]) + e->v[0]->x[1];
if ( prev > v+1e-5 )
{ dump_vislist();
printf("Bad vislist at debug_seq %d\n",debug_seq);
}
prev = v;
}
}
#endif
/***************************************************************************
*
* function: activate_edge()
*
* purpose: add edge to active edge list, if it is not there.
* Returns insertion coordinate for debugging.
* Does linear search, so could be made more efficient.
*
*/
REAL vis_eps = 1e-13; /* for equality detection */
REAL activate_edge(e)
struct vis_conedge *e;
{ struct vis_conedge *spot;
REAL v,vprev;
int seq = 0;
v = e->m*(sweep_u-e->v[0]->x[0]) + e->v[0]->x[1];
if ( e->next_active ) return v; /* already active */
PROF_START(activate_edge)
vprev = -1e30;
for ( spot = active_edge_first ; spot != NULL ; spot = spot->next_active )
{ REAL spotv = spot->m*(sweep_u-spot->v[0]->x[0]) + spot->v[0]->x[1];
if ( spotv < vprev-1e-5 )
{ sprintf(errmsg,"Internal error: visibility list out of order by %f.\n",
vprev-spotv);
kb_error(3509,errmsg,WARNING);
}
vprev = spotv; /* debugging */
spot->seqno = seq++;
if ( spotv > v+vis_eps ) break;
if ( (spotv > v-vis_eps) && (spot->m > e->m) )
break;
}
vprev = v;
/* Have now located insertion spot; "spot" comes after e */
if ( active_edge_first == spot ) active_edge_first = e;
if ( spot->prev_active ) spot->prev_active->next_active = e;
e->prev_active = spot->prev_active;
spot->prev_active = e;
e->next_active = spot;
if ( e->prev_active )
{ int i;
e->layer = (struct tsort**)temp_calloc(
e->prev_active->layers+4, sizeof(struct tsort*));
e->maxlayers = e->prev_active->layers+4;
for ( i = 0 ; i < e->prev_active->layers ; i++ )
{
add_layer(e,e->prev_active->layer[i]);
}
}
else
{ e->layer = (struct tsort**)temp_calloc(10, sizeof(struct tsort*));
e->maxlayers = 10;
}
/* update sequence numbers; time waster, but we're doing linear search
anyway. */
for ( spot = e ; spot != NULL ; spot = spot->next_active )
{ REAL spotv = spot->m*(sweep_u-spot->v[0]->x[0]) + spot->v[0]->x[1];
if ( spotv < vprev-1e-5 )
{ sprintf(errmsg,"Internal error: visibility list out of order by %f.\n",
vprev-spotv);
kb_error(2509,errmsg,WARNING);
}
vprev = spotv; /* debugging */
spot->seqno = seq++;
}
PROF_FINISH(activate_edge)
return v;
}
/*****************************************************************************
*
* function: check_deactivate()
*
* purpose: see if edge can be deleted from active list, since no longer
* separating facets.
*/
void check_deactivate(e)
struct vis_conedge *e;
{
if ( e->use_count != 0 ) return;
PROF_START(check_deactivate)
if ( e->prev_active )
e->prev_active->next_active = e->next_active;
else active_edge_first = e->next_active;
e->next_active->prev_active = e->prev_active;
find_next_event2(e->prev_active,e->next_active);
e->next_active = e->prev_active = NULL;
temp_free((char*)e->layer);
e->layer = NULL;
PROF_FINISH(check_deactivate)
}
/***************************************************************************
*
* function: facet_start_event()
*
* purpose: handle starts of two edges of facet.
*
* return: -1 if error, 1 if ok.
*/
int facet_start_event(fe)
struct vis_event *fe;
{ REAL v1,v2; /* for some debugging */
struct vis_conedge *spot;
if ( visdebuglevel >= VIS_EVENTDUMP )
printf("start edges %d %d facet %d at %20.15f\n",
fe->e1-vis_conedges,fe->e2-vis_conedges,
fe->t-vis_list, (double)sweep_u);
PROF_START(facet_start_event)
sweep_u = fe->time;
v1 = activate_edge(fe->e1); fe->e1->use_count++;
v2 = activate_edge(fe->e2); fe->e2->use_count++;
if ( v2 < v1 )
{ kb_error(2505,"Internal: Visibility list insertion out of order.\n",
WARNING);
return -1;
}
if ( fe->e1->seqno > fe->e2->seqno )
{ kb_error(2508,"Internal: Visibility list insertion out of order.\n",
WARNING);
return -1;
}
/* add this facet to layers */
for ( spot = fe->e1 ; spot != fe->e2 ; spot = spot->next_active )
{ if ( spot == NULL )
{ kb_error(2506,"Internal: Visibility list bad in facet_start_event().\n",
WARNING);
return -1;
}
add_layer(spot,fe->t);
}
PROF_FINISH(facet_start_event)
find_next_event(fe->e1);
find_next_event(fe->e2);
return 1;
} /* end facet_start_event() */
/***************************************************************************
*
* function: facet_middle_event()
*
* purpose: handle edge transition in middle of facet
*
* return: -1 for error, 1 for ok.
*/
int facet_middle_event(fe)
struct vis_event *fe;
{ struct vis_conedge *e;
if ( visdebuglevel >= VIS_EVENTDUMP )
printf("middle edges %d %d facet %d at %20.15f\n",
fe->e1-vis_conedges,fe->e2-vis_conedges,
fe->t-vis_list,(double)sweep_u);
PROF_START(facet_middle_event)
sweep_u = fe->time;
activate_edge(fe->e2); fe->e2->use_count++;
if ( fe->type == V_FACET_TOPMIDDLE )
{ if ( delete_layer(fe->e2,fe->t) )
{ /* second edge got put in the right way */
for ( e = fe->e2->next_active ; e != fe->e1 ; e = e->next_active )
{ if ( e == NULL )
{ kb_error(2575,
"Internal: Visibility list bad in facet_middle_event().\n",
WARNING);
return -1;
}
delete_layer(e,fe->t);
}
}
else /* got inserted above old edge */
{
for ( e = fe->e1; e != fe->e2 ; e = e->next_active )
{ if ( e == NULL )
{ kb_error(2507,
"Internal: Visibility list bad in facet_middle_event(). \n",
WARNING);
return -1;
}
add_layer(e,fe->t);
}
wrong_middles++;
}
}
else /* bottom middle */
{ if ( add_layer(fe->e2,fe->t) )
{ /* new edge snuck in below old */
for ( e = fe->e2->next_active ; e != fe->e1 ; e = e->next_active )
add_layer(e,fe->t);
wrong_middles++;
}
else /* new edge got in above old */
{ for ( e = fe->e1 ; e != fe->e2 ; e = e->next_active )
delete_layer(e,fe->t);
}
}
fe->e1->use_count--;
check_deactivate(fe->e1);
PROF_FINISH(facet_middle_event)
/* let event crossings take care of place in active list */
find_next_event(fe->e2);
return 1;
} /* end facet_middle_event() */
/***************************************************************************
*
* function: facet_end_event()
*
* purpose: handle deletion of active edges at end of facet
*
* return: -1 for error, 1 for ok.
*/
int facet_end_event(fe)
struct vis_event *fe;
{ struct vis_conedge *spot;
if ( visdebuglevel >= VIS_EVENTDUMP )
printf("end edges %d %d facet %d at %20.15f\n",
fe->e1-vis_conedges,fe->e2-vis_conedges,
fe->t-vis_list,(double)sweep_u);
for ( spot = fe->e1 ; spot != fe->e2 ; spot = spot->next_active )
{ if ( spot == NULL )
{ struct vis_conedge *e;
/* Oops. Something went wrong, so delete facet from entire list */
active_list_check();
for ( e = active_edge_first ; e != &sentinel ; e = e->next_active )
delete_layer(e,fe->t);
break;
}
else
delete_layer(spot,fe->t);
}
PROF_START(facet_end_event)
sweep_u = fe->time;
fe->e1->use_count--; check_deactivate(fe->e1);
fe->e2->use_count--; check_deactivate(fe->e2);
PROF_FINISH(facet_end_event)
return 1;
} /* end facet_end_event() */
/***************************************************************************
*
* function: vis_crossing()
*
* purpose: Handle crossing of two edges. Have to check to be sure
* switching order is needed, since crossing events can be
* listed twice.
*
*/
void vis_crossing(ea,eb)
struct vis_conedge *ea,*eb; /* ea below eb */
{ struct vis_conedge *te;
struct vis_rawedge *ra,*rb;
int i;
if ( ea->next_active != eb ) goto vis_crossing_exit; /* not adjacent */
if ( ea != eb->prev_active )
kb_error(2547,"Inconsistent active list.\n",RECOVERABLE);
vis_crossing_count++;
/* fix up layer lists, using info back in raw edge list */
for ( i = ea->rawstart; i <= ea->rawend ; i++ )
{ ra = rawplist[i];
if ( ra->flags & V_FACET_BOTTOM )
delete_layer(eb,ra->t);
if ( ra->flags & V_FACET_TOP )
add_layer(eb,ra->t);
}
for ( i = eb->rawstart; i <= eb->rawend ; i++ )
{ rb = rawplist[i];
if ( rb->flags & V_FACET_BOTTOM )
add_layer(ea,rb->t);
if ( rb->flags & V_FACET_TOP )
delete_layer(ea,rb->t);
}
PROF_START(vis_crossing)
/* switch order in active list */
eb->next_active->prev_active = ea;
if ( ea->prev_active ) ea->prev_active->next_active = eb;
else active_edge_first = eb;
te = ea->prev_active;
ea->prev_active = eb;
eb->prev_active = te;
te = eb->next_active;
eb->next_active = ea;
ea->next_active = te;
PROF_FINISH(vis_crossing)
/* Test for next events */
find_next_event(ea);
find_next_event(eb);
vis_crossing_exit: ;
}
/* check_layers() - Brute force check of facet layers at point. */
void check_layers(e,u,v)
struct vis_conedge *e;
REAL u,v;
{ int i,j,jj,k;
int found=0;
REAL *x[3];
REAL orientation,d;
for ( i = 0 ; i < f_event_count ; i++ )
{ struct vis_event *fe = facet_events + i;
if ( (fe->type != V_FACET_TOPMIDDLE)
&& (fe->type != V_FACET_BOTTOMMIDDLE)) continue;
x[0] = fe->e1->v[0]->x;
x[1] = fe->e1->v[1]->x;
x[2] = fe->e2->v[1]->x;
orientation = (x[1][0]-x[0][0])*(x[2][1]-x[0][1])
- (x[1][1]-x[0][1])*(x[2][0]-x[0][0]);
for ( j = 0 ; j < 3 ; j++ )
{ jj = (j==2) ? 0 : j+1;
d = (x[jj][0]-x[j][0])*(v-x[j][1])
- (x[jj][1]-x[j][1])*(u-x[j][0]);
if ( d*orientation < 0.0 )
break;
}
if ( j < 3 ) continue; /* not all on proper side */
/* now check layers */
for ( k = 0 ; k < e->layers ; k++ )
if ( fe->t == e->layer[k] )
{ found++; break; }
if ( k == e->layers )
{ fprintf(stderr,"Edge %d missing facet %d at (%f,%f).\n",e-vis_conedges,
fe->t - vis_list,u,v);
}
}
/* report */
if ( found < e->layers )
fprintf(stderr,"Edge %d extra %d layers(facet %d) at (%f,%f).\n",
e-vis_conedges,e->layers-found,e->layer[0]-vis_list,u,v);
}
/*************************************************************************
*
* function: check_visible()
*
* purpose: Inspect layers of changed edge stacks and mark topmost facets.
* Uses facet order from painter algorithm rather than
* calculating local z, since that is subject to problems with
* abutting facets.
*
*/
void check_visible(u)
REAL u; /* sweep time to check */
{ REAL v,vv; /* height on sweep line of edge and next */
int i,j;
PROF_START(check_visible)
for ( i = 0 ; i < check_list_count ; i++ )
{ struct vis_conedge *e = check_list[i];
struct tsort *topf;
e->flags &= ~V_LAYER_CHECK;
if ( e->next_active == NULL ) continue;
v = e->m*(u-e->v[0]->x[0]) + e->v[0]->x[1];
vv = e->next_active->m*(u-e->next_active->v[0]->x[0])
+ e->next_active->v[0]->x[1];
if ( fabs(v-vv) < 1e-10 ) continue; /* ignore cracks */
v = (v+vv)/2;
if ( visdebuglevel >= VIS_LAYERCHECK )
check_layers(e,u,v); /* debugging */
topf = NULL;
for ( j = 0 ; j < e->layers ; j++ )
{
struct tsort *f = e->layer[j];
if ( f > topf ) /* using painter facet order */
{ topf = f; }
}
if ( topf )
{ topf->flag |= VISIBLE;
if ( visdebuglevel >= VIS_EVENTDUMP )
printf("Marking facet %d visible.\n",topf-vis_list);
}
}
check_list_count = 0;
PROF_FINISH(check_visible)
}
#ifdef BRUTE
/*************************************************************************
Brute force visibility.
**************************************************************************/
/*************************************************************************
*
* function: brutecomp
*
* purpose: comparison function for sorting brute force event times.
*/
int brutecomp (const void *a, const void *b)
{
struct brute *aa = (struct brute *)a;
struct brute *bb = (struct brute *)b;
if ( aa->time < bb->time ) return -1;
if ( aa->time > bb->time ) return 1;
if ( aa->e1 < bb->e1 ) return -1;
if ( aa->e1 > bb->e1 ) return 1;
if ( aa->e2 < bb->e2 ) return -1;
if ( aa->e2 > bb->e2 ) return 1;
return 0;
}
/*************************************************************************
*
* function: brutecut_comp
*
* purpose: comparison function for sorting brute force cut heights.
*/
int brute_cut_comp (const void *a, const void *b)
{
struct brute_cut *aa = (struct brute_cut *)a;
struct brute_cut *bb = (struct brute_cut *)b;
if ( aa->v < bb->v ) return -1;
if ( aa->v > bb->v ) return 1;
if ( aa->e < bb->e ) return -1;
if ( aa->e > bb->e ) return 1;
return 0;
}
/***************************************************************************
*
* function: brute_section
*
* purpose: Find all edge intersections at a particular sweep position
* by brute force, and order by height.
*/
void brute_section(u)
REAL u; /* sweep position */
{ struct brute_cut *b;
int i;
struct vis_edge *e;
brute_cut_count = 0;
for ( i = 0 ; i < vecount ; i++ )
{ e = vis_edges + i;
if ( e->x[0][0] > u ) continue;
if ( e->x[1][0] < u ) continue;
b = brute_cuts + brute_cut_count++;
b->v = e->m*(u-e->x[0][0]) + e->x[0][1];
b->e = e;
}
qsort(brute_cuts,brute_cut_count,sizeof(struct brute_cut),FCAST brute_cut_comp);
}
/*************************************************************************
*
* function: brute_visible()
*
* purpose: Mark as visible those facets along sweep line, using edge
* order found by brute_section().
*
*/
struct vis_facet *brute_column[100]; /* list of facets at spot */
void brute_visible(u)
REAL u; /* sweep line position */
{ int i,j;
int depth = 0; /* number of facets stacked up */
REAL v,vv,z;
brute_section(u);
for ( i = 0 ; i < brute_cut_count-1 ; i++ )
{ struct vis_edge *e = brute_cuts[i].e;
struct vis_edge *ee = brute_cuts[i+1].e;
if ( e->flags & V_FACET_BOTTOM )
{ /* add to column */
brute_column[depth++] = e->f;
}
else if ( e->flags & V_FACET_TOP )
{ /* delete from column */
for ( j = 0 ; j < depth ; j++ )
if ( brute_column[j] == e->f )
brute_column[j] = brute_column[--depth];
}
/* check halfway in between for top facet */
v = e->m*(u-e->x[0][0]) + e->x[0][1];
vv = ee->m*(u-ee->x[0][0]) + ee->x[0][1];
if ( (depth > 0) && (fabs(v-vv) > 1e-8) )
{ REAL topz = -1e30;
int topj = -1;
v = (v+vv)/2;
for ( j = 0 ; j < depth ; j++ )
{ struct vis_facet *f = brute_column[j];
z = f->a*u + f->b*v + f->c;
if ( z > topz )
{ topj = j; topz = z; }
}
brute_column[topj]->t->flag |= VISIBLE;
}
}
}
#endif
evolver-2.30c.dfsg/src/proto.h 0000644 0001753 0001753 00000137735 11410765113 016551 0 ustar hazelsct hazelsct /*************************************************************
* This file is part of the Surface Evolver source code. *
* Programmer: Ken Brakke, brakke@susqu.edu *
*************************************************************/
/*************************************************************
*
* File: proto.h
*
* Purpose: ANSI function prototypes.
* Note: Some compilers still don't like ANSI prototypes, so
* ARGS() is a macro defined in include.h to take care
* of that.
*/
#ifdef __cplusplus
void loadstub(void);
extern "C" {
#endif
#ifndef drand48
extern double drand48 ARGS((void)); /* may not be in header file */
#endif
#ifdef MSC
extern void srand48 ARGS((int));
#endif
#ifdef MPI_EVOLVER
#include "mpi_proto.h"
#endif
void read_array_initializer ARGS((struct array *));
int simple_unstar ARGS((facetedge_id));
int check_recalc_attr ARGS((int));
void check_readonly_attr ARGS((int));
void check_special_attr ARGS((int));
int get_name_dim ARGS((int,struct locallist_t *));
int get_name_datatype ARGS((int,struct locallist_t *));
char * get_name_name ARGS((int,struct locallist_t *));
struct array *get_name_arrayptr ARGS((int,REAL*,struct locallist_t *));
int check_array_dims_same ARGS((int ,int));
void one_sided_volume_adjust ARGS((vertex_id));
int one_sided_lagrange_adjust ARGS((vertex_id));
int mat_approx_solve ARGS((REAL**,int,REAL*));
REAL vertex_total_vol_grad ARGS((vertex_id,REAL*));
void calc_one_sided_grads ARGS((void));
void mpi_hessian_cleanup ARGS((void));
void do_multigrid ARGS((struct linsys*));
void mark_recalc_params ARGS((void));
int mark_recalc_expr ARGS((struct expnode*));
int vertex_facet_check ARGS((void));
WRAPTYPE identity_inverse ARGS((WRAPTYPE));
WRAPTYPE identity_compose ARGS((WRAPTYPE,WRAPTYPE));
void identity_wrap ARGS((REAL *,REAL *,WRAPTYPE));
void identity_form_pullback ARGS((REAL *,REAL *,REAL *,WRAPTYPE));
void graph_string_facet ARGS((facet_id,struct graphdata *,int));
void plain_string_facets ARGS((void));
void print_profiling ARGS((void));
void reset_profiling ARGS((void));
void convert_constraint_to_quantities ARGS((int));
int create_body_boundary_content_method ARGS((body_id,int));
int create_body_constraint_content_method ARGS((body_id,int));
void simplex_to_fe ARGS((void));
void check_forwards ARGS((void));
int star_finagle ARGS((edge_id));
void cg_restart ARGS((void));
REAL cg_sum_calc ARGS((void));
void cg_direction_local ARGS((void));
REAL ribiere_calc ARGS((void));
REAL v_estimate ARGS((void));
void add_vgrads_to_update ARGS(( struct linsys *));
void slice_facet ARGS((struct graphdata *));
void slice_edge ARGS((struct graphdata *));
void clip_facet ARGS((struct graphdata *,facet_id,int));
void clip_edge ARGS((struct graphdata *,edge_id,int));
void graph_edge_clip ARGS((struct graphdata *,edge_id));
void mark_element_loops ARGS((struct treenode *, int));
void mem_list_dump ARGS((void));
struct element * elhash_lookup ARGS((element_id));
void elhash_delete ARGS((element_id));
void elhash_bigger ARGS((void));
void elhash_extend ARGS((int,int));
struct element *elhash_new_element ARGS((int,element_id));
void elhash_insert ARGS((element_id,struct element *));
void elhash_replace ARGS((element_id,struct element *));
void matrix_multiply_command ARGS((struct array*,struct array*,struct array*,REAL*,REAL*,REAL*));
int matrix_inverse_command ARGS((struct array*,struct array*,REAL*,REAL*));
REAL matrix_determinant_command ARGS((struct array*,REAL*));
void tree_analyze ARGS((struct linsys *));
void fixup_edge_content_meths ARGS((edge_id));
void fixup_vertex_content_meths ARGS((vertex_id));
REAL tetra_vol ARGS((REAL*,REAL*,REAL*,REAL*));
int read_single_value ARGS((int,char*));
void set_ctypes ARGS((void));
void kb_unput ARGS((char));
void list_quantity ARGS((int));
void list_method_instance ARGS((int));
void list_boundary ARGS((int));
void list_constraint ARGS((int));
void torus_unwrap_edge ARGS(( edge_id ));
int pop_vertex_to_tri ARGS(( vertex_id, edge_id *));
int pop_vertex_to_quad ARGS(( vertex_id, edge_id *));
int cubecone_pop ARGS(( vertex_id, int ));
void wrap_vertex ARGS((vertex_id,int));
void find_cpu_speed ARGS((void));
void reset_counts ARGS((void));
int pop_constrained_vertex ARGS((vertex_id));
int one_con_pop_2 ARGS((vertex_id,edge_id *,edge_id *,int));
int one_con_pop_3 ARGS((vertex_id,int ,edge_id *,edge_id *,int));
int one_con_pop_4 ARGS((vertex_id,edge_id *,int));
int double_con_pop ARGS((vertex_id,edge_id,edge_id *));
int triple_con_pop ARGS((vertex_id));
void flush_counts ARGS((void));
void merge_vertex ARGS((vertex_id,vertex_id));
void merge_edge ARGS((edge_id,edge_id));
void merge_facet ARGS((facet_id,facet_id));
void binary_tree_add ARGS((REAL*,REAL));
void torus_display_period_init ARGS((void));
REAL bezier_eval ARGS((int, int, int*, REAL *));
void bezier_convert_1D_init ARGS(( int ));
void bezier_convert_2D_init ARGS(( int ));
int t1_edgeswap ARGS((edge_id));
void get_edge_tail_tangent ARGS((edge_id,REAL*));
int valid_element ARGS((element_id));
void bezier_trans_1d ARGS((int,int,REAL**));
void bezier_eval_1d ARGS((int,int,REAL,REAL**,REAL*));
void lagrange_eval_1d ARGS((int,int,REAL,REAL**,REAL*));
void bezier_refine_1d_init ARGS((int));
void lagrange_to_bezier ARGS((void));
void bezier_to_lagrange ARGS((void));
void bezier_trans_2d ARGS((int,int,REAL**));
void lagrange_eval_2d ARGS((int,int,REAL*,REAL**,REAL*));
void bezier_eval_2d ARGS((int,int,REAL*,REAL**,REAL*));
void bezier_refine_2d_init ARGS((int));
void OFF_start ARGS((void));
void OFF_edge ARGS((struct graphdata *, edge_id));
void OFF_facet ARGS((struct graphdata *, facet_id));
void OFF_end ARGS((void));
void binary_OFF_start ARGS((void));
void binary_OFF_edge ARGS((struct graphdata *, edge_id));
void binary_OFF_facet ARGS((struct graphdata *, facet_id));
void binary_OFF_end ARGS((void));
unsigned int int32hash ARGS((unsigned int));
#ifndef NOLONGLONG
unsigned long long int64hash ARGS((unsigned long long));
#endif
void partner_move ARGS((void));
void partner_shift_grads ARGS((int));
void partner_hit_velocity_fix ARGS((void));
void partner_hit_volgrad_fix ARGS((void));
void detect_bdry_hits ARGS((void));
void thread_move_vertices ARGS((void));
void torus_period_init ARGS((void));
void set_eigenvalue_list_global ARGS((REAL*,int));
void set_view_transforms_global ARGS((void));
void set_torus_periods_global ARGS((void));
void set_inverse_periods_global ARGS((void));
void set_view_matrix_global ARGS((void));
void initialize_perm_globals ARGS((void));
void allocate_transform_colors ARGS((int));
int pop_tri_to_edge ARGS((facet_id));
int pop_edge_to_tri ARGS((edge_id));
int pop_edge_to_tri_con ARGS((edge_id));
int pop_quad_to_quad ARGS((facet_id));
void stack_usage ARGS((struct expnode *));
void list_top_procedures ARGS((int));
void list_procedure ARGS((struct global *));
void list_procedure_proto ARGS((struct global *));
void list_function_proto ARGS((struct global *));
void list_function ARGS((struct global *));
void init_local_scope ARGS((ident_t));
void exit_local_scope ARGS((void));
void begin_local_scope ARGS((void));
void end_local_scope ARGS((void));
void locals_copy ARGS((struct locallist_t **,struct locallist_t *));
void locals_copy_perm ARGS((struct locallist_t **,struct locallist_t *));
ident_t lookup_local_var ARGS((char*));
ident_t add_local_var ARGS((char*,int));
void read_attribute_value ARGS((struct extra *, void*));
int equiangulate_edge ARGS((edge_id));
int calc_view_transform_gens ARGS((void));
void force_project ARGS(( REAL*, vertex_id, REAL *));
int global_meth_needs ARGS((int));
int pop_given_vertex ARGS((vertex_id));
int pop_string_vertex ARGS((vertex_id));
void print_array ARGS((struct array *,void*));
void print_array_attribute ARGS(( struct extra*, void*));
void recalc_facet_area ARGS((facet_id));
void rewind_globals ARGS((int));
void perm_rewind_globals ARGS((int));
void add_warning_message ARGS((char*));
void graph_new_surface ARGS((void));
void LD_solve ARGS((REAL**,REAL*,REAL*,int));
int LD_factor ARGS(( REAL**, int ));
int lookup_global_hash ARGS((char*,int,int,int));
void dy_check ARGS((void));
void report_quantities ARGS((void));
void list_free ARGS((char *,int));
void list_free_all ARGS((int));
#ifdef MEMSTRINGS
char * list_calloc ARGS((size_t,size_t,int,char*,size_t));
char * list_realloc ARGS((char *,size_t,int,char*,size_t));
#else
char * list_calloc ARGS((size_t,size_t,int));
char * list_realloc ARGS((char *,size_t,int));
#endif
void mem_list_summary ARGS((void));
void mem_check_sanity ARGS((void));
void change_hessian_functions ARGS((int,int));
int LD_block_factor ARGS((REAL **, int));
void LD_block_solve ARGS((REAL **, REAL *, REAL *, int));
int find_fixed ARGS((void));
void sp_hash_init ARGS((struct linsys *,int));
void sp_hash_expand ARGS((struct linsys *));
void sp_hash_search ARGS((struct linsys *,int,int,REAL));
int sp_hash_end ARGS((struct linsys *,int,int,int));
void my_pvm_exit ARGS((void));
void pvm_calc_quants ARGS((int));
void pvm_calc_quant_grads ARGS((int));
void pvm_facet_knot_init ARGS((REAL*));
int two_split ARGS((facetedge_id,int));
int vertex_degfree ARGS((vertex_id));
int edge_degfree ARGS((edge_id));
int facet_degfree ARGS((facet_id));
void divide_quad ARGS((facetedge_id));
int pop_one_edge ARGS((edge_id));
void set_scroll_size ARGS((int));
REAL ellipticK ARGS((REAL));
REAL ellipticE ARGS((REAL));
REAL ellipticKdm ARGS((REAL));
REAL ellipticEdm ARGS((REAL));
REAL ellipticKdmdm ARGS((REAL));
REAL ellipticEdmdm ARGS((REAL));
REAL incompleteEllipticF ARGS((REAL,REAL));
REAL incompleteEllipticFdphi ARGS((REAL,REAL));
REAL incompleteEllipticFdm ARGS((REAL,REAL));
REAL incompleteEllipticFseconds ARGS((REAL,REAL,REAL*,REAL*,REAL*,REAL*,REAL*));
REAL incompleteEllipticE ARGS((REAL,REAL));
REAL incompleteEllipticEdphi ARGS((REAL,REAL));
REAL incompleteEllipticEdm ARGS((REAL,REAL));
REAL incompleteEllipticEseconds ARGS((REAL,REAL,REAL*,REAL*,REAL*,REAL*,REAL*));
int INDEX_TO_RGBA ARGS((int));
void multi_calc_quants ARGS((int));
void m_fix_grads ARGS((void));
void m_calc_quant_grads ARGS((int));
int mylock_web ARGS((void));
int myunlock_web ARGS((void));
int mylock_element ARGS((element_id));
int myunlock_element ARGS((element_id));
element_id thread_next_element ARGS((void));
void thread_launch ARGS((int,int));
void thread_project_all ARGS((int));
void thread_calc_facet_energy ARGS((void));
void thread_calc_facet_forces ARGS((void));
REAL interp_edge_attribute ARGS(( edge_id ,struct extra *, int ,int));
REAL interp_facet_attribute ARGS(( edge_id ,struct extra *, int ,int));
REAL get_extra_attrib_value ARGS(( element_id, struct extra *, int));
void define_array ARGS((void));
void userfunc_init ARGS((void));
void break_check ARGS((void));
int lagrange_facet_normal ARGS((vertex_id,facet_id,REAL**));
void test_axial_points ARGS(( facet_id ));
int compare_edge_attr ARGS((edge_id, edge_id));
int compare_edge_facet_attr ARGS((edge_id,facet_id));
int compare_vertex_edge_attr ARGS((vertex_id, edge_id));
int compare_vertex_attr ARGS((vertex_id, vertex_id));
void set_body_volume ARGS((body_id,REAL,int));
void add_body_volume ARGS((body_id,REAL));
void add_body_volume_plain ARGS((body_id,REAL));
void add_body_abstotal ARGS((body_id,REAL));
void set_body ARGS((facet_id,body_id));
int kb_yylex ARGS((YYSTYPE*));
void reset_inputbuffer ARGS((void));
char *my_fgets ARGS((char *,int,FILE *stream));
int method_check ARGS((void));
void renumber_all ARGS((void));
void reorder_storage ARGS((void));
int identtype ARGS((char*));
REAL kb_drand ARGS((void));
void kb_initr ARGS((int));
void dump_macros ARGS((void));
void move_to_free_front ARGS((int,int));
void calc_all_grads ARGS((int));
void check_pinning ARGS((void));
void convert_forms_to_vectors ARGS((int));
void local_convert_forms_to_vectors ARGS((int));
void clear_v_conmap ARGS((vertex_id ));
void list_attributes ARGS((void));
void reset_rot_order ARGS((void));
void start_logfile ARGS((char*));
void stop_logfile ARGS((void));
void start_keylogfile ARGS((char*));
void stop_keylogfile ARGS((void));
void one_sided_adjust ARGS((int));
void calc_leftside ARGS((void));
void local_calc_leftside ARGS((void));
void local_calc_rightside ARGS((void));
void load_library ARGS((char *));
void unload_libraries ARGS((void));
dll_func_type search_libraries ARGS((char*));
REAL get_internal_variable ARGS((int ));
void check_element_type ARGS(( int, int ));
int read_pick ARGS((void));
int count_fixed_vol ARGS((void));
int oid ARGS((element_id));
void flip_toggle ARGS((int*,int,char*));
int gram_schmidt ARGS((REAL**,int,int));
int new_vertex_average ARGS((vertex_id,int));
int lagrange_vertex_average ARGS((vertex_id,REAL*));
void keyword_help ARGS((char *));
void error_help ARGS((char *));
void write_to_console ARGS((char *));
void read_line_from_console ARGS((char *));
int do_edgeswap ARGS((edge_id));
void apply_h_inverse_metric ARGS((void));
void list_proc ARGS((struct global *,int));
void list_procedures ARGS((int));
void linear_to_lagrange ARGS((int));
void quad_to_lagrange ARGS((int));
void lagrange_to_linear ARGS((void));
void lagrange_to_quad ARGS((void));
void sparse_permute ARGS((struct linsys *));
void do_tree_factor ARGS((struct linsys *));
void do_tree_solve ARGS((struct linsys *,REAL *,REAL*));
int find_method_instance ARGS((char*));
int find_quantity ARGS((char*));
void reconvert_bodies_to_quantities ARGS((void));
void convert_bodies_to_quantities ARGS((void));
int string_rebody ARGS((void));
void lagrange_to_lagrange ARGS((int));
void simplex_lagrange_to_lagrange ARGS((int));
void metis_partition ARGS((int,int));
void metis_partition_plain ARGS((int,int));
void metis_partition_body ARGS((int,int));
void metis_partition_dual ARGS((int,int));
void metis_order ARGS((struct linsys *));
void metis_vertex_order ARGS((int));
int lagrange_index ARGS((int,int,int*));
int increment_lagrange_index ARGS((int,int*));
void gauss_lagrange_setup ARGS((int,int,int));
void det_hess ARGS((REAL **,REAL ****,int ));
int simplex_delete_facet ARGS((facet_id));
int simplex_delete_edge ARGS((vertex_id,vertex_id));
void write_hessian ARGS((struct linsys *));
REAL gravity_all ARGS((struct qinfo *,int));
void LQ_decomp ARGS((REAL**,int,int,REAL**,REAL**,struct linsys *));
void q_info_free ARGS((struct qinfo *));
void q_info_init ARGS((struct qinfo *,int));
void make_el_list ARGS((int));
int Ord ARGS((element_id));
void toggle_save ARGS((char*));
void toggle_save_off ARGS((char*));
int get_v_constraint_status ARGS((vertex_id,int));
int v_hit_constraint_count ARGS((vertex_id));
REAL square_grad ARGS((void));
void square_grad_forces ARGS((void));
void cg_ritz ARGS((struct linsys *,int,REAL**,REAL*));
int check_pick ARGS((void));
void read_extra ARGS((element_id,int));
int simplex_quadrature ARGS((int,int,int,REAL**,REAL*));
int eartest ARGS((vertex_id,vertex_id));
void convert_string ARGS((char*,char*));
void hessian_legal ARGS((void));
int check_one_sided_constraints ARGS((void));
void set_v_global ARGS((vertex_id));
void set_v_conmap ARGS((vertex_id,conmap_t*));
void set_e_conmap ARGS((edge_id,conmap_t*));
void set_f_conmap ARGS((facet_id,conmap_t*));
void set_v_constraint_map ARGS((vertex_id,int));
void unset_v_constraint_map ARGS((vertex_id,int));
void set_v_constraint_status ARGS((vertex_id,int));
void unset_v_constraint_status ARGS((vertex_id,int));
void clear_v_constraint_status ARGS((vertex_id));
void set_e_constraint_map ARGS((edge_id,int));
void unset_e_constraint_map ARGS((edge_id,int));
void set_f_constraint_map ARGS((facet_id,int));
void unset_f_constraint_map ARGS((facet_id,int));
int v_on_constraint ARGS((vertex_id,int));
int e_on_constraint ARGS((edge_id,int));
int f_on_constraint ARGS((facet_id,int));
void get_v_common_conmap ARGS((vertex_id,vertex_id,conmap_t *));
int simplex_tiny_edges ARGS((REAL));
int get_tag ARGS((facet_id));
void set_tag ARGS((facet_id,int));
void ritz_command ARGS((REAL,int));
void do_ritz ARGS((struct linsys *,REAL,int,REAL **));
void print_hessian_menu ARGS((void));
void expand_attribute ARGS((int,int,int*));
void expand_global_hash ARGS((void));
int edgeswap ARGS(( edge_id));
REAL sparse_metric_dot ARGS((REAL*,REAL*,struct linsys *));
void gauss_jacobi ARGS((int, REAL , REAL *, REAL *));
void jacobi_eigenpairs ARGS(( REAL **, int, REAL *, REAL **, REAL *));
void star_metric_setup ARGS(( struct linsys *S, struct linsys *));
void linear_metric_setup ARGS((struct linsys *, struct linsys *));
void linear_metric_setup_quadratic ARGS(( struct linsys *, struct linsys *));
void linear_metric_setup_lagrange ARGS(( struct linsys *, struct linsys *));
REAL get_vertex_length_star ARGS((vertex_id));
REAL get_vertex_area_star ARGS((vertex_id));
void convert_to_quantities ARGS((void));
void convert_body_to_quantity ARGS((body_id));
void convert_new_body_to_quantity ARGS((body_id));
void long_jiggle ARGS((void));
void free_system ARGS((struct linsys *));
int simplex_long_edges ARGS((REAL));
void lanczos_command ARGS((REAL,int));
void eigenprobe_command ARGS((REAL,int));
void myfree ARGS((char *));
void option_facet ARGS((struct graphdata*,facet_id));
void geomview_command ARGS((char*));
void ysmp_numeric_factor ARGS((void));
void sp_hessian_mult ARGS((struct linsys *S, REAL *B, REAL *C));
void sp_solution ARGS((struct linsys *S, REAL *B, REAL *C));
void hessian_exit ARGS((REAL *));
void hessian_cleanup ARGS((void));
void hessian_solve ARGS((void));
void hessian_downhill ARGS((void));
void hessian_move ARGS((REAL,int,REAL *));
int lanczos ARGS((struct linsys*,int,REAL*,int));
int selective_lanczos ARGS((struct linsys*,int,REAL*,int));
void tridiag_QL ARGS((REAL*,REAL*,int));
void intersect_detect ARGS((void));
void bk_mul ARGS((struct linsys *, REAL*,REAL*));
void bk_AIJ_setup ARGS((int,struct linsys*));
void bk_eigenprobe ARGS((struct linsys *));
void bk_inverse_it ARGS((struct linsys *, REAL *));
void sp_hessian_solve ARGS((struct linsys *,REAL *, REAL *,int));
void sp_hessian_solve_multi ARGS((struct linsys *,REAL **, REAL **,int));
void sp_Hessian_solver ARGS((struct linsys *, REAL *, REAL **));
void bk_constraint_setup ARGS((int, struct linsys *));
void BK_hess_project_setup ARGS((struct linsys *));
void xmd_factor ARGS((struct linsys *));
void xmd_solve ARGS((struct linsys *,REAL *,REAL *));
void xmd_solve_multi ARGS((struct linsys *,REAL **,REAL **,int));
void sp_CHinvC ARGS((struct linsys *));
void tree_factor ARGS((struct linsys *));
void tree_solve ARGS((struct linsys *,REAL *,REAL *));
void tree_solve_multi ARGS((struct linsys *,REAL **,REAL **,int));
void ysmp_factor ARGS((struct linsys *));
void ysmp_solve ARGS((struct linsys *,REAL *,REAL *));
void ysmp_solve_multi ARGS((struct linsys *,REAL **,REAL **,int));
void find_ordering ARGS((struct hess_verlist *,int,int *));
void hessian_saddle ARGS((REAL));
REAL lowest_eigenpair ARGS((struct linsys *,REAL *));
REAL cg_lowest_eigenpair ARGS((struct linsys *,REAL *));
REAL old_cg_lowest_eigenpair ARGS((struct linsys *,REAL *));
REAL new_cg_lowest_eigenpair ARGS((struct linsys *,REAL *));
element_id get_ordinal_id ARGS((int,int));
element_id get_full_id ARGS((int,element_id));
void project_all ARGS((int,int));
void chebychev_hess ARGS((struct linsys *));
void chebychev_ev ARGS((struct linsys *));
void fill_self_entry ARGS((struct linsys *,vertex_id,REAL**));
void fill_grad ARGS((struct linsys *,struct hess_verlist *,REAL*,REAL *));
int add_attribute ARGS((int,char*,int,int,int*,int,struct expnode *));
int find_attribute ARGS((int,char*));
int find_extra ARGS((char *, int *));
int matrix_index ARGS((REAL**,int));
int exec_commands ARGS((FILE *,char *));
void *mac_exec_commands ARGS((FILE *));
void push_fd ARGS((FILE *,char *));
void pop_fd ARGS((void));
facet_id get_vertex_facet ARGS((vertex_id));
facet_id get_vertex_first_facet ARGS((vertex_id));
facet_id get_next_vertex_facet ARGS((vertex_id,facet_id));
facet_id get_simplex_next_vertex_facet ARGS((vertex_id,facet_id));
void macro_init ARGS((void));
REAL ** mat2d_setup ARGS((REAL**,REAL*,int,int));
REAL *** mat3d_setup ARGS((REAL***,REAL*,int,int,int));
REAL **** mat4d_setup ARGS((REAL****,REAL*,int,int,int,int));
void zerohess ARGS((struct qinfo *));
void get_facet_normal ARGS((facet_id,REAL*));
int get_toggle_value ARGS((int));
REAL user_attribute ARGS((element_id));
void force_normalization ARGS((void));
void insert_vertex_edge ARGS((vertex_id,edge_id));
void remove_vertex_edge ARGS((vertex_id,edge_id));
void insert_vertex_facet ARGS((vertex_id,facet_id));
void remove_vertex_facet ARGS((vertex_id,facet_id));
void catfulltext ARGS((char*));
int identcase ARGS((char*));
int eliminate_facet ARGS((facet_id));
int string_eliminate_facet ARGS((facet_id));
REAL quantity_attribute ARGS(( element_id, int ));
REAL instance_attribute ARGS(( element_id, int ));
int kb_checksum ARGS((char *,int));
void apply_quantity ARGS((element_id,int));
void unapply_quantity ARGS((element_id,int));
void read_instance_attr ARGS(( int ));
int read_named_quantity ARGS((void));
DY_OFFSET dy_calloc ARGS((int,int));
DY_OFFSET dy_realloc ARGS((DY_OFFSET,int,int));
void dy_free ARGS((DY_OFFSET));
void dump_method_specs ARGS(( int ));
void read_method_attr ARGS(( int ));
void calc_periods ARGS((int));
int read_method_instance ARGS((void));
int add_standard_quantity ARGS((char *,REAL));
int new_method_instance ARGS((char*,char*));
int attach_method ARGS(( int, char *));
int attach_method_num ARGS(( int, int));
void apply_method ARGS(( element_id , char *));
void apply_method_num ARGS(( element_id , int));
void unapply_method ARGS(( element_id , int));
int rebody ARGS((void));
int merge_bodies ARGS((void));
int get_body_valence ARGS((body_id ));
int get_vertex_evalence ARGS((vertex_id ));
int get_vertex_fvalence ARGS((vertex_id ));
void make_vfacet_lists ARGS((void));
void make_bfacet_lists ARGS((void));
void make_vedge_lists ARGS((void));
REAL dirichlet ARGS((int));
REAL sobolev ARGS((int));
int unstar ARGS((facetedge_id));
void reduce_string ARGS((char *));
REAL vertex_angle ARGS((vertex_id));
void fix_ctm ARGS((REAL**,REAL,REAL));
void my_exit ARGS((int));
void reverse_orientation_edge ARGS((edge_id));
void reverse_orientation_facet ARGS((facet_id));
int dissolve_vertex ARGS((vertex_id));
int dissolve_edge ARGS((edge_id));
int dissolve_facet ARGS((facet_id));
int dissolve_body ARGS((body_id));
REAL vertex_sq_mean_curvature ARGS((vertex_id));
REAL vertex_mean_curvature ARGS((vertex_id));
void burchard ARGS((int));
void do_gfile ARGS((int,char*));
int mat_simplify ARGS((REAL***,int));
void transform_gen_expr ARGS((char *));
void generate_transforms ARGS((int));
void read_transform_generators ARGS((int));
int const_expr ARGS((char *,REAL *));
REAL wedge_angle ARGS((vertex_id));
void begin_normal_motion ARGS((void));
void end_normal_motion ARGS((void));
REAL gray_level ARGS((float *));
void metric_form_to_vector ARGS((REAL*,REAL*));
void end_geomview_object ARGS((void));
void calc_quant_grads ARGS((int));
int simplex_element_id_edges ARGS((REAL));
void quantity_init ARGS((void));
int new_quantity ARGS((char *,int));
void add_quantity ARGS((element_id,char*,char*));
REAL calc_quants ARGS((int));
void graph_edge_transforms ARGS(( struct graphdata *, edge_id ));
void graph_facet_transforms ARGS(( struct graphdata *, facet_id ));
void other_stuff ARGS((struct treenode *,int*,int*,element_id,REAL*,struct locallist_t*));
void more_other_stuff ARGS((struct treenode *,int*,int*,element_id,REAL*,struct locallist_t*));
void ask_wrap_display ARGS((void));
void print_attr ARGS(( struct treenode *, char *));
void print_set_attr ARGS(( struct treenode *, char *));
void set_print ARGS((struct treenode *, char *, char *,int));
void binary_print ARGS(( struct treenode *, int, int, char *, int));
int lookup_global ARGS((char*));
int lookup_perm_global ARGS((char*));
void klein_area_grad ARGS((REAL **,REAL**));
REAL klein_area ARGS((REAL**));
void klein_length_grad ARGS((REAL*,REAL*,REAL*,REAL*));
REAL klein_length ARGS((REAL*,REAL*));
void geomview_start ARGS((void));
void geomview_facet ARGS((struct graphdata *, facet_id));
void geomview_edge ARGS((struct graphdata *, edge_id));
void geomview_end ARGS((void));
void tree_copy ARGS(( struct expnode *, struct treenode *));
void perm_tree_copy ARGS(( struct expnode *, struct treenode *));
void conf_edge_curv_energy ARGS((void));
void conf_edge_curv_force ARGS((void));
REAL dihedral ARGS((edge_id));
void clear_symtable ARGS((void));
void clear_globals ARGS((void));
int add_global ARGS((char *));
int add_perm_global ARGS((char *));
char *keywordname ARGS((int));
void subtree_swap ARGS((int*,int*));
int begin_scope ARGS((void));
void end_scope ARGS((void));
void set_scope ARGS((int));
struct sym * symbol_add ARGS((char*,int));
struct sym *symbol_lookup ARGS((char*));
vertex_id void_test ARGS((vertex_id *,int));
char *tokname ARGS((int));
void update_aggr ARGS((int ,REAL *,REAL ));
void hessian_init ARGS((struct linsys *,REAL **));
void hessian_fill ARGS((struct linsys *,REAL **));
void find_hess_entry ARGS((struct linsys *, struct hess_verlist*,
struct hess_entry *[MAXCOORD][MAXCOORD]));
void fill_hess_entry ARGS((struct linsys *, vertex_id,REAL**));
int find_mixed_entry ARGS((struct linsys *, struct hess_verlist*,
struct hess_verlist* ,struct hess_entry *[MAXCOORD][MAXCOORD]));
void fill_mixed_entry ARGS((struct linsys *, vertex_id,vertex_id, REAL **));
int find_hess_entries ARGS((struct linsys *, struct hess_verlist*,
struct hess_verlist*,
struct hess_entry *[MAXCOORD][MAXCOORD],
struct hess_entry *[MAXCOORD][MAXCOORD],
struct hess_entry *[MAXCOORD][MAXCOORD]));
void area_hessian ARGS((struct linsys *,REAL *));
void calc_quant_hess ARGS((struct linsys *,int,int,REAL *));
void m_calc_quant_hess ARGS((int,int,REAL *));
void m_fix_hess ARGS((struct linsys *S));
void difference_hessian ARGS((struct linsys *,struct hess_verlist*,REAL *));
void edge_energy_hessian ARGS((struct linsys *,REAL *));
void simplex_hessian ARGS((struct linsys *,REAL *));
void simplex_facet_hessian ARGS((struct linsys *,REAL *));
void simplex_edge_hessian ARGS((struct linsys *,edge_id,REAL**,REAL****));
void edge_constr_hessian ARGS((struct linsys *,edge_id,REAL**,REAL****));
int body_hessian ARGS((struct linsys *,REAL*));
void tree_exec ARGS(( struct treenode *));
void letter_command ARGS((int));
void pop_commandfd ARGS((void));
void push_commandfd ARGS((FILE*,char*));
void pop_datafd ARGS((void));
void push_datafd ARGS((FILE*,char*));
void exec_file ARGS((FILE*,char*));
void unput_tok ARGS((void));
void unput_string ARGS((char*));
void set_f_phase_density ARGS((facet_id));
void set_e_phase_density ARGS((edge_id));
int bdry_basis ARGS((vertex_id,REAL**));
int constr_basis ARGS((vertex_id,REAL**));
void sp_factor ARGS((struct linsys *));
void stability_test ARGS((void));
void mobility_cleanup ARGS((void));
void mobility_mult ARGS((REAL*));
void mobility_setup ARGS((void));
void approx_curv_calc ARGS((int));
void approx_curvature ARGS((void));
int new_popverst ARGS((vertex_id,int));
void phase_initialize ARGS((char *));
void check_vertex_fe ARGS((vertex_id));
void information ARGS((void));
void show_volumes ARGS((void));
int set_parameters ARGS((void));
int minus_type ARGS((int));
void string_fixup ARGS((void));
void runge_kutta ARGS((void));
void autopop_init ARGS((void));
void autopop_cleanup ARGS((void));
void autopop_pop ARGS((void));
void autochop_chop ARGS((void));
void autopop_detect ARGS((REAL));
vertex_id find_other_vertex ARGS((vertex_id *,int,vertex_id));
void simplex_delaunay_test ARGS((void));
void push_face ARGS((vertex_id *));
int pop_face ARGS((vertex_id *));
void end_face_stack ARGS((void));
void init_face_stack ARGS((int));
int simplex_equiangulate ARGS((void));
void calc_simplex_edge_force ARGS((edge_id));
int kernel_basis ARGS((REAL**,REAL**,int,int));
int kernel_basis_rows ARGS((REAL**,REAL**,int,int));
void tr_mat_mul ARGS((REAL**,REAL**,REAL**,int,int,int));
void mat_mul_tr ARGS((REAL**,REAL**,REAL**,int,int,int));
void mat_tsquare ARGS((REAL**,REAL**,int,int));
void calc_simplex_edge_energy ARGS((edge_id));
void exterior_product ARGS((REAL **,REAL *,int,int));
int binom_coeff ARGS((int,int));
void hi_dim_graph ARGS((void));
void recalc ARGS((void));
void reset_conj_grad ARGS((void));
void kusner_energy ARGS((void));
void kusner_force ARGS((void));
void sqgauss_energy ARGS((void));
void sqgauss_force ARGS((void));
int prompt ARGS((char*,char*,int));
#ifdef USE_READLINE /* CSL */
void save_readline_history ARGS((void));
#endif
void update_display ARGS((void));
void local_update_display ARGS((void));
void set_spinr ARGS((REAL));
void set_spinl ARGS((REAL));
void set_tipup ARGS((REAL));
void set_tipdown ARGS((REAL));
void set_clockwise ARGS((REAL));
void set_counterclockwise ARGS((REAL));
void set_zoom ARGS((REAL));
void skinny_histogram ARGS((void));
int skinny ARGS((REAL));
int get_edge_valence ARGS((edge_id));
int get_facet_valence ARGS((edge_id));
void alice ARGS((void));
void sqcurve_force_string ARGS((vertex_id));
void sqcurve_force_string_end ARGS((void));
void sqcurve_energy_string ARGS((vertex_id));
void sqcurve_energy_string_init ARGS((void));
void bad_function ARGS((void));
void sqcurve_force_init ARGS((void));
void sqcurve_energy_init ARGS((void));
void sqcurve_energy ARGS((vertex_id*, REAL (*)[MAXCOORD]));
void sqcurve_force ARGS((vertex_id*,edge_id*,REAL(*)[MAXCOORD]));
void sqcurve_energy_end ARGS((void));
void sqcurve_force_end ARGS((void));
void top_dump ARGS((FILE *));
void bottom_dump ARGS((FILE *));
void vertex_dump ARGS((vertex_id,FILE *));
void edge_dump ARGS((edge_id,FILE *));
void facet_dump ARGS((facet_id,FILE *));
void facetedge_dump ARGS((facetedge_id,FILE *));
void body_dump ARGS((body_id,FILE *));
WRAPTYPE torus_inverse ARGS((WRAPTYPE));
WRAPTYPE torus_compose ARGS((WRAPTYPE,WRAPTYPE));
void torus_wrap ARGS((REAL *,REAL *,WRAPTYPE));
void torus_form_pullback ARGS((REAL *,REAL *,REAL *,WRAPTYPE));
WRAPTYPE group_inverse ARGS((WRAPTYPE));
WRAPTYPE group_compose ARGS((WRAPTYPE,WRAPTYPE));
void group_wrap ARGS((REAL *,REAL *,WRAPTYPE));
void group_form_pullback ARGS((REAL *,REAL *,REAL *,WRAPTYPE));
void print_matrix ARGS(( REAL **, int , int ));
REAL simplex_energy_metric ARGS((vertex_id*,REAL * *));
void simplex_force_metric ARGS((vertex_id *,REAL**, REAL,REAL **));
void gauss_setup ARGS((void));
void simplex_grad_l ARGS((void));
void end_hash_table ARGS((void));
void rehash ARGS((void));
void init_hash_table ARGS((void));
void check_orientation ARGS((struct simplex *,int));
void refine_simplex_init ARGS((void));
void refine_simplex ARGS((int,int *,struct divedge *,struct simplex *));
void refine_all_simplices ARGS((void));
vertex_id simplex_edge_divide ARGS((vertex_id,vertex_id));
int poponest ARGS((vertex_id,int));
void free_discards ARGS((int));
int find_vertex_to_pop ARGS((void));
void puff ARGS((void));
REAL splinepoly ARGS((int,REAL));
REAL splinederiv ARGS((int,REAL));
void spline_partial ARGS((int *,REAL,int,REAL *));
void spline_partial_t ARGS((int *,REAL,REAL *));
void dump_buff ARGS((char*,size_t));
int command ARGS((char *,int));
void newcommand ARGS((char *));
void new_history ARGS((char *));
int old_history ARGS((char *));
int qqparse ARGS((void));
#ifdef MEMSTRINGS
char *kb_calloc ARGS((size_t,size_t,char*,size_t));
char *KB_realloc ARGS((char*,size_t,char*,size_t));
char *kb_temp_calloc ARGS((size_t,size_t,char*,size_t));
char *kb_temp_realloc ARGS((char*,size_t,char*,size_t));
#else
char *kb_calloc ARGS((size_t,size_t));
char *KB_realloc ARGS((char*,size_t));
char *kb_temp_calloc ARGS((size_t,size_t));
char *kb_temp_realloc ARGS((char*,size_t));
#endif
void temp_free ARGS((char *));
void temp_free_all ARGS((void));
void cg_direction ARGS((void));
void cg_calc_gamma ARGS((void));
void simplex_facet_average ARGS((facet_id,int));
void facet_average ARGS((facet_id,int));
void edge_average ARGS((edge_id,int));
void recalc_verts ARGS((void));
void grule ARGS((int , REAL *, REAL *));
void read_facet_edges ARGS((void));
void read_faces ARGS((void));
void read_edges ARGS((void));
void read_vertices ARGS((void));
void read_bodies ARGS((void));
int read_quantity ARGS((void));
int read_const ARGS((REAL *));
void lowbound ARGS((void));
void ridge_histogram ARGS((void));
int collapse_check ARGS((void));
#ifndef TCPP
int vvvvcomp ARGS((struct vvvv *,struct vvvv *));
#endif
void End_OOGL ARGS((void ));
void End_geomview ARGS((void ));
void UpdateOOGL ARGS((void ));
void Begin_OOGL ARGS((void ));
void Begin_geomview ARGS((char*));
void softimage ARGS((void ));
void constraint_init ARGS((struct constraint *));
void constraint_free ARGS((struct constraint *));
REAL find_flux ARGS((facet_id));
int is_constant ARGS((int));
void free_expr ARGS((struct expnode *));
void perm_free_expr ARGS((struct expnode *));
void startup ARGS((char *));
void reset_view ARGS((void));
void read_parameter ARGS((void));
void read_transforms ARGS((int));
void zoom_vertex ARGS((vertex_id,REAL));
REAL distance ARGS((vertex_id,vertex_id));
void merge_collapsed_facets ARGS((void));
void constr_vol_grad_q ARGS((edge_id));
void homothety ARGS((void));
void ex_fold ARGS((struct treenode *));
void fold_recur ARGS((struct treenode *, int *));
int yybegin ARGS((void));
void yylex_init ARGS((void));
int yyerror ARGS((char *));
int yyparse ARGS((void));
int yylook ARGS((void));
int yywrap ARGS((void));
int yylex ARGS((void));
int yyreject ARGS((void));
int gettok ARGS((int));
int kb_input ARGS((void));
void rawunput ARGS((int));
int macro ARGS((void));
void record_macro ARGS((void));
void fe_reorder ARGS((edge_id));
void pix_start ARGS((void));
void pix_facet ARGS((struct graphdata *,facet_id));
void pix_end ARGS((void));
void constr_edge_force_q ARGS((edge_id));
void restore_vertex ARGS((vertex_id,struct oldcoord *,int));
REAL normal_change_check ARGS((void));
FILE *path_open ARGS((char *,int));
void fil_finish ARGS((void));
void fil_facet ARGS((struct tsort *));
void fil_edge ARGS((struct tsort *));
void fil_init ARGS((void));
void ps_finish ARGS((void));
void ps_facet ARGS((struct tsort *));
void ps_edge ARGS((struct tsort *));
void ps_init ARGS((void));
void display_file ARGS((int));
void graph_help ARGS((void));
void main_help ARGS((void));
REAL edge_grav_density ARGS((edge_id));
int facet_body_check ARGS((void));
int facetedge_check ARGS((int));
int list_check ARGS((void));
int run_checks ARGS((void));
int pop_vertex ARGS((vertex_id,int));
int kraynik_pop ARGS((vertex_id,int));
int popfilm ARGS((void));
void face_triangulate ARGS((facet_id,int));
void file_wulff ARGS((REAL *,REAL *));
void lens_wulff ARGS((REAL *,REAL *));
void hemi_wulff ARGS((REAL *,REAL *));
int curtest_facet ARGS((facet_id));
int curtest_edge ARGS((edge_id,facetedge_id,facetedge_id));
void curtest ARGS((void));
void fix_volconst ARGS((void));
element_id upgrade ARGS((element_id));
facet_id dup_facet ARGS((facet_id));
body_id dup_body ARGS((body_id));
REAL estimate_decrease ARGS((void));
void constr_edge_content_q ARGS((edge_id));
void constr_edge_energy_q ARGS((edge_id));
void tordup ARGS((int));
void add_outside ARGS((void));
REAL calc_content ARGS((int));
void local_calc_content ARGS((int));
int equal_constr ARGS((element_id ,element_id));
void bdry_spring_energy ARGS((edge_id));
void constr_spring_energy ARGS((edge_id));
void torus_cells ARGS((void));
void torus_edge_clip ARGS((struct graphdata *,int ));
void torus_arc_clip ARGS((struct graphdata *,int ));
void null_function ARGS((void));
void diffuse ARGS((void));
int cone_analyze ARGS((struct verfacet *,int));
vertex_id dup_vertex ARGS((vertex_id));
edge_id dup_edge ARGS((edge_id));
void versplit ARGS((facetedge_id ,facetedge_id,int));
int try_prop ARGS((facetedge_id *, facetedge_id,int));
int edgepop_film ARGS((void));
char * print_express ARGS((struct expnode *,int));
void exprint_recur ARGS((struct treenode *,int));
char *kb_strstr ARGS((char *,char *));
int kb_stricmp ARGS((char *,char *));
int kb_strnicmp ARGS((char *,char *, int));
void kb_memmove ARGS((char *,char *,size_t));
int pixdump ARGS((void));
void constr_springs ARGS((edge_id));
void save_coords ARGS((struct oldcoord *,int));
void local_save_coords ARGS((struct oldcoord *,int));
void restore_coords ARGS((struct oldcoord *,int));
void local_restore_coords ARGS((struct oldcoord *,int));
void unsave_coords ARGS((struct oldcoord *,int));
void local_unsave_coords ARGS((struct oldcoord *,int));
void enforce_constraints ARGS((void));
void kb_strupr ARGS((char *));
void b_proj ARGS((struct boundary *,REAL *,REAL * *,int, vertex_id ));
void b_extrapolate ARGS((struct boundary *,REAL *,REAL *,REAL *,REAL *,
REAL *,vertex_id));
void bdry_force ARGS((edge_id ));
void calc_bdry_force_v ARGS((vertex_id ));
void calc_bdry_force_e ARGS((edge_id ));
void calc_bdry_energy_v ARGS((vertex_id ));
void calc_bdry_energy_e ARGS((edge_id ));
void calc_bdry_content_v ARGS((vertex_id ));
void calc_bdry_content_e ARGS((edge_id ));
void calc_force ARGS((void ));
void local_calc_force ARGS((void ));
void calc_energy ARGS((void));
void local_calc_energy ARGS((void));
void calc_pressure ARGS((void ));
void display ARGS((void ));
int constr_proj ARGS((int ,int ,struct constraint * *,REAL *,REAL *,
REAL *,int *,int,vertex_id));
int constr_proj_matrix ARGS(( vertex_id, REAL ** ));
int constr_proj_matrix_wall ARGS(( vertex_id, REAL ** ));
int project_v_constr ARGS((vertex_id,int,int ));
void calc_constr_force_v ARGS((vertex_id ));
void calc_constr_force_e ARGS((edge_id ));
void calc_constr_energy_v ARGS((vertex_id ));
void calc_constr_energy_e ARGS((edge_id ));
void calc_constr_content_v ARGS((vertex_id ));
void calc_constr_content_e ARGS((edge_id ));
void dump ARGS((void ));
void do_dump ARGS((char *));
REAL eval ARGS((struct expnode *,REAL *,element_id,struct eval_frame*));
void eval_all ARGS((struct expnode *,REAL *,int,REAL *,REAL *,element_id));
void eval_second ARGS((struct expnode *,REAL *,int,REAL *,REAL *,
REAL**,element_id));
REAL tree_eval ARGS((struct treenode *,REAL *));
REAL eval_deriv ARGS((struct expnode *,REAL *,int ));
REAL tree_eval_deriv ARGS((struct treenode *,REAL *,int ));
int exparse ARGS((int ,struct expnode *,int));
void calc_simplex_forces ARGS((facet_id));
void calc_simplex_energy ARGS((facet_id));
void calc_simplex_volume ARGS((facet_id));
void facet_force_l ARGS((facet_id ));
void facet_energy_l ARGS((facet_id,int));
void facet_force_l_hi_d ARGS((facet_id ));
void facet_energy_l_hi_d ARGS((facet_id));
void facet_volume_l ARGS((facet_id ));
void film_grad_l ARGS((void ));
void film_bdry_grad ARGS((void ));
void film_constr_grad ARGS((void ));
void facet_force_q ARGS((facet_id ));
void facet_energy_q ARGS((facet_id,int ));
void facet_volume_q ARGS((facet_id ));
void film_grad_q ARGS((void ));
REAL tq7_integral ARGS((REAL (*)(REAL,REAL)));
REAL intpoly6 ARGS((int ,REAL ,REAL ));
REAL intpoly6part ARGS((int ,int ,REAL ,REAL ));
REAL vintzf ARGS((REAL ,REAL ));
void vcoeff_init ARGS((void ));
void calc_volgrads ARGS((int));
void local_calc_volgrads ARGS((int));
void pressure_forces ARGS((void));
void calc_lagrange ARGS((void));
void lagrange_adjust ARGS((void));
int local_lagrange_adjust ARGS((void));
void volume_restore ARGS((REAL,int));
void local_volume_restore ARGS((REAL,int));
int graphgen ARGS((void ));
void plain_facets ARGS((void ));
void plain_edges ARGS((void ));
void bare_edges ARGS((void ));
void triple_edges ARGS((void ));
void torus_clip ARGS((struct graphdata *,int, facet_id ));
int bfcomp ARGS((struct bodyface *,struct bodyface *));
void torus_bodies ARGS((void ));
void reset_web ARGS((void ));
void initialize ARGS((void));
void read_periods ARGS((void ));
void read_display_periods ARGS((void ));
void wulff_initialize ARGS((char *));
int read_boundary ARGS((void));
int read_constraint ARGS((void));
void read_surface_energy ARGS((void));
void iterate ARGS((void ));
void fix_vertices ARGS((void ));
void move_vertices ARGS((int,REAL ));
void local_move_vertices ARGS((int,REAL ));
void jiggle ARGS((void ));
void element_id_jiggle ARGS((void ));
REAL gaussian ARGS((void ));
void nrerror ARGS((char *));
void matcopy ARGS((REAL * *,REAL * *,int ,int ));
REAL **perm_matrix2 ARGS((int,int));
#ifdef MEMSTRINGS
REAL * *kb_dmatrix ARGS((int ,int ,int ,int,char*,int ));
REAL * * * kb_dmatrix3 ARGS((int ,int ,int,char*,int ));
REAL * * * * kb_dmatrix4 ARGS((int ,int ,int, int,char*,int ));
REAL * *kb_temp_dmatrix ARGS((int ,int ,int ,int,char*,int ));
REAL * * * kb_temp_dmatrix3 ARGS((int ,int ,int,char*,int ));
REAL * * * * kb_temp_dmatrix4 ARGS((int ,int ,int, int,char*,int ));
#else
REAL * *kb_dmatrix ARGS((int ,int ,int ,int ));
REAL * * * kb_dmatrix3 ARGS((int ,int ,int ));
REAL * * * * kb_dmatrix4 ARGS((int ,int ,int, int ));
REAL * *kb_temp_dmatrix ARGS((int ,int ,int ,int ));
REAL * * * kb_temp_dmatrix3 ARGS((int ,int ,int ));
REAL * * * * kb_temp_dmatrix4 ARGS((int ,int ,int, int ));
#endif
REAL *** matrix3_reorder ARGS((REAL***,int,int,int));
int *ivector ARGS((int ,int ));
REAL *vector ARGS((int ,int ));
void free_ivector ARGS((int *,int ,int ));
void free_vector ARGS((REAL *,int ,int ));
void free_matrix ARGS((REAL * *));
void free_matrix3 ARGS((REAL * * *));
void free_matrix4 ARGS((REAL * * * *));
void free_temp_matrix ARGS((REAL * *));
void free_temp_matrix3 ARGS((REAL * * *));
void free_temp_matrix4 ARGS((REAL * * * *));
void vector_add ARGS((REAL*,REAL*,int));
void vector_add_smul ARGS((REAL*,REAL*,REAL,int));
void vector_sub ARGS((REAL*,REAL*,int));
void vnormal ARGS((REAL *,REAL *,REAL *,REAL *));
void cross_prod ARGS((REAL *,REAL *,REAL *));
REAL triple_prod ARGS((REAL *,REAL *,REAL *));
REAL dot ARGS((REAL *,REAL *,int ));
REAL dotf ARGS((float *,float *,int ));
REAL dotdf ARGS((REAL *,float *,int ));
void matvec_mul ARGS((REAL * *,REAL *,REAL *,int ,int ));
void vec_mat_mul ARGS((REAL *,REAL ** ,REAL *,int ,int ));
void mat_mult ARGS((REAL * *,REAL * *,REAL * *,int ,int ,int ));
REAL quadratic_form ARGS((REAL *,REAL **,REAL *,int));
int mat_inv ARGS((REAL * *,int ));
int mat_inv_sym ARGS((REAL * *,int ));
int mat_inv_sparse ARGS((REAL * *,int ));
REAL determinant ARGS((REAL * *,int ));
REAL det_adjoint ARGS((REAL * *,int ));
void change_model ARGS((void ));
void linear_to_quad ARGS((void ));
void quad_to_linear ARGS((void ));
edge_id edge_divide ARGS((edge_id ));
void cross_cut ARGS((facetedge_id ,facetedge_id ));
void painter_start ARGS((void ));
void painter_facet ARGS((struct graphdata *,facet_id ));
void painter_end ARGS((void ));
int in_back ARGS((struct tsort *,struct tsort *));
int separating_plane ARGS((struct tsort *,struct tsort *,int));
int separating_line ARGS((struct tsort *,struct tsort *));
void painter_edge ARGS((struct graphdata *,edge_id));
int verpop_film ARGS((void ));
void do_save ARGS((void ));
void do_restore ARGS((void ));
int odd4cone_pop ARGS((vertex_id,int));
void set_facet_fe ARGS((facet_id ,facetedge_id ));
vertex_id new_vertex ARGS((REAL *,element_id));
edge_id new_edge ARGS((vertex_id ,vertex_id,element_id ));
facet_id new_facet ARGS((void ));
body_id new_body ARGS((void ));
facetedge_id new_facetedge ARGS((facet_id ,edge_id ));
REAL get_edge_length ARGS((edge_id ));
REAL get_facet_pressure ARGS((facet_id ));
#ifndef elptr
struct element *elptr ARGS((element_id ));
#endif
void extend ARGS((int,int));
void expand ARGS((int,int ));
void unfree_element ARGS((element_id));
int generate_all ARGS((int ,element_id *,element_id *));
void memory_report ARGS((void ));
void reset_skeleton ARGS((void ));
void vgrad_init ARGS((int ));
void vgrad_end ARGS((void ));
struct volgrad *get_vertex_vgrad ARGS((vertex_id));
void set_vertex_vgrad ARGS((vertex_id,struct volgrad*));
struct volgrad *get_next_vgrad ARGS((struct volgrad *));
struct volgrad *new_vgrad ARGS((void ));
struct volgrad *get_bv_vgrad ARGS((int ,vertex_id ));
struct volgrad *get_bv_new_vgrad ARGS((int ,vertex_id ));
element_id new_element ARGS((int,element_id,element_id));
void free_element ARGS((element_id ));
void edge_force_l ARGS((edge_id ));
void edge_energy_l ARGS((edge_id ));
void edge_area_l ARGS((edge_id ));
void edge_force_l_metric ARGS((edge_id ));
void edge_energy_l_metric ARGS((edge_id ));
void edge_force_q_metric ARGS((edge_id ));
void edge_energy_q_metric ARGS((edge_id ));
void string_grad_l ARGS((void ));
void string_bdry_grad ARGS((void ));
void string_constr_grad ARGS((void ));
REAL interpoly ARGS((int ,REAL ));
REAL interpolyderiv ARGS((int ,REAL ));
void scoeff_init ARGS((void ));
void edge_force_q ARGS((edge_id ));
void edge_energy_q ARGS((edge_id ));
void edge_area_q ARGS((edge_id ));
void string_grad_q ARGS((void ));
void do_show ARGS((void ));
int view_transform ARGS((char *));
void init_view ARGS((void ));
void resize ARGS((void ));
int old_menu ARGS((char * ));
void extrapolate ARGS((void ));
void save ARGS((void ));
void restore ARGS((char *));
void torvol ARGS((void));
void torvol_project ARGS((int ));
void refine ARGS((void ));
void local_refine ARGS((void ));
int areaweed ARGS((REAL ));
void area_histogram ARGS((void ));
int edgeweed ARGS((REAL ));
void edge_histogram ARGS((void ));
int eliminate_edge ARGS((edge_id ));
void change_vertex ARGS((facetedge_id ,vertex_id ,vertex_id ,WRAPTYPE));
int articulate ARGS((REAL ));
edge_id edge_refine ARGS((edge_id ));
int equiangulate ARGS((void ));
int ridge_notcher ARGS((REAL ));
void outstring ARGS(( CONST char *));
void erroutstring ARGS((char *));
void getstring ARGS((char *,int));
void kb_error ARGS((int, char *,int ));
void catcher ARGS((int ));
void calc_edge ARGS((edge_id ));
void get_edge_side ARGS((edge_id ,REAL *));
void get_edge_adjust ARGS((edge_id ,REAL *));
REAL calc_vertex_normal ARGS((vertex_id,facetedge_id ,REAL *));
void calc_vertex_smooth_normal ARGS((vertex_id,facetedge_id ,REAL *));
int new_calc_vertex_normal ARGS((vertex_id,REAL **));
int project_vertex_normals ARGS(( vertex_id, REAL **, int ));
int simplex_vertex_normal ARGS((vertex_id,REAL **));
void get_edge_verts ARGS((edge_id ,REAL * *,WRAPTYPE*));
void get_facet_verts ARGS((facet_id ,REAL * *,WRAPTYPE*));
void get_facet_verts_special ARGS((facet_id ,REAL * *,WRAPTYPE*));
void get_facet_verts_q ARGS((facet_id ,REAL * *,WRAPTYPE*));
int verpop_str ARGS((void ));
void dump_force ARGS((void));
void vertex_average ARGS((int));
void hessian_menu ARGS((void));
void hessian_auto ARGS((void));
REAL hessian_seek ARGS((REAL));
REAL hessian_line_seek ARGS((struct linsys *,REAL,REAL*));
void set_facet_body ARGS((facet_id ,body_id ));
int makenode ARGS((NTYPE,NTYPE,NTYPE));
void set_body_fixvol ARGS((body_id,REAL));
facet_id get_next_body_facet ARGS((facet_id));
facet_id get_prev_body_facet ARGS((facet_id));
void set_next_vertex_facet ARGS((vertex_id,facet_id,facet_id));
void set_next_body_facet ARGS((facet_id,facet_id));
void set_prev_body_facet ARGS((facet_id,facet_id));
void set_fe_facet ARGS((facetedge_id ,facet_id ));
#if !defined (INLINE)
/* some functions replaced by macros in serial version */
int get_meth_offset ARGS((int));
char *get_extra ARGS((element_id,int));
char *get_extra_ptr ARGS((element_id,struct extra *));
void set_body_volconst ARGS((body_id,REAL));
void set_fe_edge ARGS((facetedge_id ,edge_id ));
facet_id get_fe_facet ARGS((facetedge_id ));
facetedge_id get_prev_facet ARGS((facetedge_id ));
facetedge_id get_next_facet ARGS((facetedge_id ));
void set_prev_edge ARGS((facetedge_id ,facetedge_id ));
void set_next_edge ARGS((facetedge_id ,facetedge_id ));
void set_prev_facet ARGS((facetedge_id ,facetedge_id ));
void set_next_facet ARGS((facetedge_id ,facetedge_id ));
void set_edge_wrap ARGS((edge_id ,WRAPTYPE ));
WRAPTYPE get_edge_wrap ARGS((edge_id ));
void set_edge_fe ARGS((edge_id ,facetedge_id ));
facetedge_id get_edge_fe ARGS((edge_id ));
void set_edge_tailv ARGS((edge_id ,vertex_id ));
void set_edge_headv ARGS((edge_id ,vertex_id ));
void set_edge_midv ARGS((edge_id ,vertex_id ));
body_id get_facet_body ARGS((facet_id ));
facetedge_id get_facet_fe ARGS((facet_id ));
void set_attr ARGS((element_id ,ATTR ));
void unset_attr ARGS((element_id ,ATTR ));
edge_id get_fe_edge ARGS((facetedge_id));
facetedge_id get_prev_edge ARGS((facetedge_id ));
facetedge_id get_next_edge ARGS((facetedge_id ));
vertex_id get_edge_tailv ARGS((edge_id ));
vertex_id get_edge_headv ARGS((edge_id ));
edge_id get_next_tail_edge ARGS((edge_id));
edge_id get_next_head_edge ARGS((edge_id));
void set_next_tail_edge ARGS((edge_id,edge_id));
facetedge_id get_body_fe ARGS((body_id));
facetedge_id get_body_facet ARGS((body_id));
void set_body_facet ARGS((body_id,facetedge_id));
REAL get_body_density ARGS((body_id));
REAL get_body_abstotal ARGS((body_id));
REAL get_body_volume ARGS((body_id));
REAL get_body_fixvol ARGS((body_id));
REAL get_body_pressure ARGS((body_id));
REAL get_body_volconst ARGS((body_id));
void set_body_density ARGS((body_id,REAL));
void set_body_pressure ARGS((body_id,REAL));
facetedge_id get_vertex_fe ARGS((vertex_id));
#endif
#ifdef __cplusplus
}
#endif
evolver-2.30c.dfsg/src/express.h 0000644 0001753 0001753 00000065262 11410765113 017072 0 ustar hazelsct hazelsct /*************************************************************
* This file is part of the Surface Evolver source code. *
* Programmer: Ken Brakke, brakke@susqu.edu *
*************************************************************/
/********************************************************************
*
* File: express.h
*
* Contents: defines for expression parsing and evaluation.
*/
#ifdef __cplusplus
extern "C" {
#endif
/* node types, numbered above 1512 to avoid yacc token numbers */
#define GEN_ERROR_TOKEN 10000
#define IMMEDIATE_AUTOPOP_ 2337
#define PROCEDURE_CALL_RETURN_ 2336
#define FUNCTION_CALL_RETURN_ 2335
#define SETUP_FRAME_ 2334
#define CONTENT_RANK_ 2333
#define SLICE_COEFF 2332
#define CLIP_COEFF 2331
#define AUTOPOP_QUARTIC_ 2330
#define STAR_FINAGLING_ 2329
#define FORCE_DELETION_ 2328
#define DEFINE_FIXED_LOCAL_ARRAY_ 2327
#define ARRAY_VERTEX_NORMAL_ 2326
#define ARRAY_EDGE_VECTOR_ 2325
#define ARRAY_FACET_NORMAL_ 2324
#define PRINT_ARRAY_LVALUE_ 2323
#define ARRAY_EVAL_ 2322
#define PRINT_PROFILING_ 2321
#define ARRAY_ASSIGNOP_FACET_NORMAL_ 2320
#define ARRAY_ASSIGNOP_EDGE_VECTOR_ 2319
#define ARRAY_ASSIGNOP_VERTEX_NORMAL_ 2318
#define ARRAY_ASSIGNOP_SINGLE_ 2317
#define ARRAY_LVALUE_INDEXED_ 2316
#define ATTRIB_LVALUE_ 2315
#define ARRAY_RVALUE_ 2314
#define ARRAY_ASSIGNOP_ARRAY_ 2312
#define ARRAY_ASSIGNOP_SCALAR_ 2311
#define ARRAY_ASSIGNOP_S_X_A_ 2310
#define ARRAY_ASSIGNOP_A_P_A_ 2309
#define ARRAY_ASSIGNOP_A_S_A_ 2308
#define V_HIGH_BOUNDARY 2307
#define V_HIGH_CONSTRAINT 2306
#define LOCAL_LIST_START_ 2305
#define CLIP_VIEW_ 2304
#define V_STRING_CURVE_TOLERANCE 2303
#define TEXT_SPOT_ 2302
#define WHEREAMI_COMMAND_ 2301
#define UNSET_BREAKPOINT_ 2300
#define SET_BREAKPOINT_ 2299
#define PUSH_PARAM_FIXED 2298
#define V_CORONA_STATE 2297
#define PUSH_ELEMENT_ID_ 2296
#define ELINDEX_ 2295
#define SET_CONSTRAINT_GLOBAL 2294
#define UNSET_CONSTRAINT_GLOBAL 2293
#define SET_CONSTRAINT_NAME_GLOBAL 2292
#define UNSET_CONSTRAINT_NAME_GLOBAL 2291
#define FUNCTION_QUANTITY_SPARSE_ 2290
#define SLICE_VIEW_ 2289
#define V_MPI_MAXTASK 2288
#define DISPLAY_ORIGIN_ 2287
#define V_AUTOCHOP_LENGTH 2286
#define QUIETLOAD_ 2285
#define LITTLE_ENDIAN_ 2284
#define BIG_ENDIAN_ 2283
#define BINARY_PRINTFHEAD_ 2282
#define V_FACET_REVERSE_COUNT 2281
#define V_EDGE_REVERSE_COUNT 2280
#define V_THIS_TASK 2279
#define POP_ENJOIN_ 2278
#define V_WINDOW_ASPECT_RATIO 2277
#define PRINT_SINGLE_LETTER_ 2276
#define PDELTA_LVALUE_ 2275
#define PSCALE_LVALUE_ 2274
#define INIT_VERTEX_EDGE_ 1513
#define INIT_VERTEX_FACET_ 1514
#define INIT_VERTEX_BODY_ 1515
#define INIT_EDGE_VERTEX_ 1516
#define INIT_EDGE_FACET_ 1517
#define INIT_EDGE_BODY_ 1518
#define INIT_FACET_VERTEX_ 1519
#define INIT_FACET_EDGE_ 1520
#define INIT_FACET_BODY_ 1521
#define INIT_BODY_VERTEX_ 1522
#define INIT_BODY_EDGE_ 1523
#define INIT_BODY_FACET_ 1524
#define NEXT_VERTEX_EDGE_ 1525
#define NEXT_VERTEX_FACET_ 1526
#define NEXT_VERTEX_BODY_ 1527
#define NEXT_EDGE_VERTEX_ 1528
#define NEXT_EDGE_FACET_ 1529
#define NEXT_EDGE_BODY_ 1530
#define NEXT_FACET_VERTEX_ 1531
#define NEXT_FACET_EDGE_ 1532
#define NEXT_FACET_BODY_ 1533
#define NEXT_BODY_VERTEX_ 1534
#define NEXT_BODY_EDGE_ 1535
#define NEXT_BODY_FACET_ 1536
#define NEXT_VERTEX_ 1537
#define NEXT_EDGE_ 1538
#define NEXT_FACET_ 1539
#define NEXT_BODY_ 1540
#define NEXT_ELEMENT_ 1541
#define INIT_VERTEX_ 1542
#define INIT_EDGE_ 1543
#define INIT_FACET_ 1544
#define INIT_BODY_ 1545
#define INIT_ELEMENT_ 1546
#define SET_GRAVITY_ 1547
#define SET_DIFFUSION_ 1548
#define SET_GLOBAL_ 1549
#define SET_COLOR_ 1550
#define SET_DENSITY_ 1551
#define SET_PRESSURE_ 1552
#define SET_VOLUME_ 1553
#define SET_CONSTRAINT_ 1554
#define SET_TAG_ 1555
#define SET_OPACITY_ 1556
#define SET_SCALE_ 1557
#define SET_COORD_ 1558
#define SET_COORD_1 1559
#define SET_COORD_2 1560
#define SET_COORD_3 1561
#define SET_COORD_4 1562
#define SET_COORD_5 1563
#define SET_COORD_6 1564
#define SET_COORD_7 1565
#define SET_COORD_8 1566
#define SET_PROCEDURE_ 1567
#define SET_PROC_END_ 1568
#define SET_AUTOCHOP_ 1570
#define SET_GAP_CONSTANT_ 1571
#define SET_AMBIENT_PRESSURE_ 1572
#define SET_FIXED_AREA_ 1573
#define SET_COLORMAP_ 1574
#define SET_THICKEN_ 1575
#define SET_BACKGROUND_ 1576
#define SET_OPTIMIZE_ 1577
#define SET_FIXED_ 1578
#define GET_FIXED_ 1579
#define GET_LENGTH_ 1580
#define GET_VALENCE_ 1581
#define GET_AREA_ 1582
#define GET_VOLUME_ 1583
#define GET_DENSITY_ 1584
#define GET_ID_ 1585
#define GET_TAG_ 1586
#define GET_ORIGINAL_ 1587
#define INIT_AVG_ 1588
#define INIT_SUM_ 1589
#define INIT_MAX_ 1590
#define INIT_MIN_ 1591
#define INIT_COUNT_ 1592
#define AGGREGATE_INIT_ 1593
#define AGGREGATE_END_ 1594
#define AGGREGATE_ 1595
#define SET_INIT_ 1596
#define UNSET_CONSTRAINT_ 1597
#define UNSET_BOUNDARY_ 1598
#define GET_COLOR_ 1599
#define GET_SQ_MEAN_CURV_ 1600
#define GET_INTERNAL_ 1601
#define V_VERTEXCOUNT 1602
#define V_EDGECOUNT 1603
#define V_FACETCOUNT 1604
#define V_BODYCOUNT 1605
#define V_FACETEDGECOUNT 1606
#define V_ENERGY 1607
#define V_AREA 1608
#define V_LENGTH 1609
#define V_SCALE 1610
#define LIST_PROCS_ 1611
#define PRINTFHEAD_ 1612
#define PREPRINTF_ 1613
#define EXPRLIST_ 1614
#define SPRINTFHEAD_ 1615
#define SET_SGLOBAL_ 1616
#define GET_OID_ 1617
#define GET_FRONTCOLOR_ 1618
#define GET_BACKCOLOR_ 1619
#define SET_FRONTCOLOR_ 1620
#define SET_BACKCOLOR_ 1621
#define SET_PARAM_ 1622
#define SET_PARAM_1 1623
#define SET_PARAM_2 1624
#define SET_PARAM_3 1625
#define SET_PARAM_4 1626
#define SET_PARAM_5 1627
#define SET_PARAM_6 1628
#define SET_PARAM_7 1629
#define SET_ATTRIBUTE_ 1630
#define SET_PHASE_ 1631
#define GET_PHASE_ 1632
#define LEXERROR 1633
#define PRESPRINTF_ 1634
#define V_SURFACE_DIMENSION 1635
#define V_SPACE_DIMENSION 1636
#define TOGGLEVALUE 1637
#define V_TORUS 1638
#define V_TORUS_FILLED 1639
#define V_SYMMETRY_GROUP 1640
#define V_SIMPLEX 1641
#define V_INTEGRAL_ORDER 1642
#define GET_STAR_ 1643
#define GET_PRESSURE_ 1644
#define SET_INTERNAL_ 1645
#define V_TOLERANCE 1646
#define AUTODISPLAY_ 1647
#define V_EQUI_COUNT 1648
#define V_DELETE_COUNT 1650
#define V_REFINE_COUNT 1651
#define V_NOTCH_COUNT 1652
#define V_DISSOLVE_COUNT 1653
#define V_POP_COUNT 1654
#define V_WHERE_COUNT 1655
#define PUSH_NAMED_QUANTITY 1656
#define SET_NAMED_QUANTITY_ 1657
#define GET_USERATTR_ 1658
#define GET_QUANTITY_ 1659
#define UNSET_NAMED_QUANTITY_ 1660
#define GET_WRAP_ 1661
#define FINISHED 1701
#define PUSHCONST 1702
#define PUSHPARAM 1703
#define PUSHPI 1704
#define PUSHE 1705
#define PLUS 1706
#define MINUS 1707
#define TIMES 1708
#define DIVIDE 1709
#define INTPOW 1710
#define POW 1711
#define SIN 1712
#define COS 1713
#define TAN 1714
#define SQRT 1715
#define LOG 1716
#define EXP 1717
#define COPY 1718
#define ACOS 1719
#define ASIN 1720
#define ATAN 1721
#define CHS 1722
#define INV 1723
#define SQR 1724
#define PUSHG 1725
#define EQUATE 1726
#define PUSHADJUSTABLE 1727
#define ABS 1728
#define USERFUNC 1729
#define REPEAT_ 1730
#define FULLEXPR 1731
#define SINH 1732
#define COSH 1733
#define REPLACECONST 1734
#define REALMOD 1735
#define CEIL_ 1736
#define FLOOR_ 1737
#define ATAN2_ 1738
#define NOP_ 1739
#define V_HESS_EPSILON 1740
#define HESSIAN_DIFF_ 1741
#define SHOW_INNER_ 1742
#define SHOW_OUTER_ 1743
#define CLIPPED_CELLS_ 1744
#define RAW_CELLS_ 1745
#define CONNECTED_CELLS_ 1746
#define NORMAL_MOTION_ 1747
#define RUNGE_KUTTA_ 1748
#define DETURCK_ 1749
#define KUSNER_ 1750
#define VIEW_4D_ 1751
#define CONF_EDGE_SQCURV_ 1752
#define SQGAUSS_ 1753
#define AUTOPOP_ 1754
#define OLD_AREA_ 1755
#define APPROX_CURV_ 1756
#define CHECK_INCREASE_ 1757
#define DEBUG_ 1758
#define MEMDEBUG_ 1759
#define EFFECTIVE_AREA_ 1760
#define ESTIMATE_ 1761
#define POST_PROJECT_ 1762
#define TRANSFORMS_ 1763
#define QUIET_ 1764
#define CONJ_GRAD_ 1765
#define HOMOTHETY_ 1766
#define FACET_COLORS_ 1767
#define SHADING_ 1768
#define DIV_NORMAL_CURVATURE_ 1769
#define NORMAL_CURVATURE_ 1770
#define BOUNDARY_CURVATURE_ 1771
#define SELF_SIMILAR_ 1772
#define GV_BINARY_ 1773
#define METRIC_CONVERSION_ 1774
#define AUTORECALC_ 1775
#define PINNING_ 1776
#define FORCE_POS_DEF_ 1777
#define V_SCALE_SCALE 1778
#define GET_EXTRA_ATTR_ 1779
#define SET_EXTRA_ATTR_ 1780
#define SET_ATTRIBUTE_LOOP_ 1781
#define SET_ATTRIBUTE_L 1782
#define TANH 1783
#define ATANH 1784
#define ASINH 1785
#define ACOSH 1786
#define V_ITER_COUNTER 1787
#define QUIETGO_ 1788
#define GET_MIDV_ 1789
#define RIBIERE_CG_ 1790
#define ASSUME_ORIENTED_ 1791
#define HESSIAN_QUIET_ 1792
#define CONJUNCTION_END 1793
#define JIGGLE_TOGGLE_ 1794
#define V_TIME 1795
#define V_JIG_TEMP 1796
#define SYMBOL_ELEMENT_ 1797
#define SINGLE_ELEMENT_ 1798
#define INDEXED_SUBTYPE_ 1799
#define INDEXED_ATTRIBUTE 1800
#define QUALIFIED_ATTRIBUTE 1801
#define STRPRINT_ 1802
#define GET_TRIPLE_PT_ 1804
#define SET_TRIPLE_PT_ 1805
#define GET_TETRA_PT_ 1806
#define SET_TETRA_PT_ 1807
#define UNSET_TETRA_PT_ 1808
#define UNSET_TRIPLE_PT_ 1809
#define PUSHQPRESSURE_ 1810
#define PUSHQTARGET_ 1811
#define PUSHQVALUE_ 1812
#define PUSHQMODULUS_ 1813
#define SET_QMODULUS_ 1814
#define SET_QTARGET_ 1815
#define YSMP_ 1816
#define BUNCH_KAUFMAN_ 1817
#define V_EIGENPOS 1818
#define V_EIGENNEG 1819
#define V_EIGENZERO 1820
#define QUANTITIES_ONLY_ 1821
#define EVERYTHING_QUANTITIES_ 1822
#define METRIC_CONVERT_ 1823
#define GET_TARGET_ 1824
#define MAXIMUM_ 1825
#define UNSET_FACET_BODY_ 1826
#define SET_ORIENTATION_ 1827
#define V_PICKVNUM 1828
#define V_PICKENUM 1829
#define V_PICKFNUM 1830
#define LINEAR_METRIC_ 1831
#define V_LINEAR_METRIC_MIX 1832
#define INVOKE_P_MENU_ 1833
#define GEOMVIEW_TOGGLE_ 1834
#define DO_TOP_ 1835
#define DO_END_ 1836
#define DO_ENTRY_ 1837
#define SET_MODEL_ 1838
#define V_RANDOM_SEED 1839
#define MINIMUM_ 1840
#define V_INTEGRAL_ORDER_1D 1841
#define V_INTEGRAL_ORDER_2D 1842
#define GET_ORIENTATION_ 1843
#define SET_TARGET_ 1844
#define UNSET_FIXED_ 1845
#define UNSET_DENSITY_ 1846
#define UNSET_VOLUME_ 1847
#define UNSET_PRESSURE_ 1848
#define UNSET_TARGET_ 1849
#define GET_VOLCONST_ 1850
#define SET_VOLCONST_ 1851
#define GET_TORUS_PERIODS_ 1852
#define PUSHQVOLCONST_ 1853
#define GET_FIXEDVOL_ 1854
#define SET_QVOLCONST_ 1855
#define SET_QPARAMETER_1_ 1856
#define PUSHQPARAMETER_1_ 1857
#define SINGLE_ELEMENT_INIT_ 1858
#define REDEFINE_SINGLE_ 1859
#define UNREDEFINE_SINGLE_ 1860
#define V_QUADRATIC_METRIC_MIX 1861
#define GEOMPIPE_TOGGLE_ 1862
#define V_LAST_EIGENVALUE 1863
#define V_LAST_HESSIAN_SCALE 1864
#define SQUARED_GRADIENT_ 1865
#define PRINT_LETTER_ 1866
#define REDIRECT_END_ 1867
#define PIPE_END_ 1868
#define V_LAGRANGE_ORDER 1869
#define SET_AXIAL_POINT_ 1870
#define UNSET_AXIAL_POINT_ 1871
#define GET_AXIAL_POINT_ 1872
#define H_INVERSE_METRIC_ 1873
#define HELP_KEYWORD 1874
#define SKINNY_ 1875
#define TORDUP_ 1876
#define V_GAP_CONSTANT 1877
#define V_THICKNESS 1878
#define V_TARGET_TOLERANCE 1879
#define V_CLOCK 1880
#define FIX_QUANTITY_ 1881
#define UNFIX_QUANTITY_ 1882
#define SET_ORIGINAL_ 1883
#define V_SCALE_LIMIT 1884
#define SET_MMODULUS_ 1885
#define GET_INSTANCE_ 1886
#define PUSHMMODULUS_ 1887
#define PUSHMVALUE_ 1888
#define PSCOLORFLAG_ 1889
#define GRIDFLAG_ 1890
#define CROSSINGFLAG_ 1891
#define LABELFLAG_ 1892
#define SHOW_ALL_QUANTITIES_ 1893
#define GET_INVERSE_PERIODS_ 1894
#define CREATE_EDGE_ 1895
#define SET_NO_REFINE_ 1896
#define UNSET_NO_REFINE_ 1897
#define GET_NO_REFINE_ 1898
#define CREATE_VERTEX_ 1899
#define CREATE_FACET_ 1900
#define CREATE_BODY_ 1901
#define SET_FRONTBODY_ 1902
#define SET_BACKBODY_ 1903
#define V_TRANSFORM_COUNT 1904
#define GT_ 1905
#define LT_ 1906
#define GET_BACKBODY_ 1907
#define GET_FRONTBODY_ 1908
#define GET_TRANSFORM_EXPR_ 1909
#define LOGFILE_TOGGLE_ 1910
#define SET_WRAP_ 1911
#define PLUSASSIGN_ 1912
#define SUBASSIGN_ 1913
#define MULTASSIGN_ 1914
#define DIVASSIGN_ 1915
#define NULLBLOCK_ 1916
#define SINGLE_ASSIGN_ 1917
#define SET_ATTRIBUTE_A 1918
#define SET_METHOD_INSTANCE_ 1919
#define UNSET_METHOD_INSTANCE_ 1920
#define PUSH_METHOD_INSTANCE_ 1921
#define LIST_ATTRIBUTES_ 1922
#define NULLCMD_ 1923
#define FIX_PARAMETER_ 1924
#define UNFIX_PARAMETER_ 1925
#define ITDEBUG_ 1926
#define ZENER_DRAG_ 1927
#define VOLGRADS_EVERY_ 1928
#define V_RANDOM 1929
#define PUSHQTOLERANCE_ 1930
#define SET_QTOLERANCE_ 1931
#define PUSHDELTA_ 1932
#define SET_DELTA_ 1933
#define BACKCULL_ 1934
#define V_BRIGHTNESS 1935
#define V_DIFFUSION 1936
#define DEFINE_IDENT_ 1937
#define V_BACKGROUND 1938
#define SET_NO_DISPLAY_ 1939
#define UNSET_NO_DISPLAY_ 1940
#define GET_NO_DISPLAY_ 1941
#define V_MEMARENA 1942
#define V_MEMUSED 1943
#define INDEXED_COORD_ 1944
#define V_LAST_ERROR 1945
#define VERBOSE_ 1946
#define ACOMMANDEXPR_ 1947
#define CMDLIST_ 1948
#define ULONG_TYPE_ 1949
#define INDEXED_ELEMENT_ 1950
#define MEAN_CURV_ 1951
#define REPEAT_INIT_ 1952
#define SYMATTR_ 1953
#define INIT_SUBELEMENT_ 1954
#define GET_DIHEDRAL_ 1955
#define INIT_FACETEDGE_ 1956
#define GET_EDGE_ 1957
#define GET_FACET_ 1958
#define NEXT_FACETEDGE_ 1959
#define PUSHGLOBAL_ 1960
#define COMMAND_BLOCK_ 1961
#define IFTEST_ 1962
#define WHILE_TOP_ 1963
#define WHILE_END_ 1964
#define PRINT_PROCEDURE_ 1965
#define SHOW_END_ 1966
#define AMBIENT_PRESSURE_ 1967
#define INTERP_NORMALS_ 1969
#define MEAN_CURV_INT_ 1970
#define COND_TEST_ 1971
#define COND_EXPR_ 1972
#define COND_ELSE_ 1973
#define BACKGROUND_ 1974
#define V_AMBIENT_PRESSURE 1975
#define V_HESSIAN_SLANT_CUTOFF 1976
#define WRAP_COMPOSE_ 1977
#define WRAP_INVERSE_ 1978
#define GET_VERTEXNORMAL_ 1979
#define SET_VIEW_MATRIX_ 1980
#define VIEW_MATRIX_LVALUE_ 1981
#define ACTUAL_VOLUME_ 1982
#define SELF_ELEMENT_ 1983
#define UNSET_FRONTBODY_ 1984
#define UNSET_BACKBODY_ 1985
#define V_CHECK_COUNT_ 1986
#define V_BREAKFLAG_ 1987
#define SET_CONSTRAINT_NAME 1988
#define UNSET_CONSTRAINT_NAME 1989
#define SET_BOUNDARY_NAME 1990
#define UNSET_BOUNDARY_NAME 1991
#define ON_CONSTRAINT_NAME 1992
#define HIT_CONSTRAINT_NAME 1993
#define ON_BOUNDARY_NAME 1994
#define SET_PARAM_SCALE 1995
#define PUSH_PARAM_SCALE 1996
#define EXPRINT_PROCEDURE_ 1997
#define ERRPRINTFHEAD_ 1998
#define INDEXSET_ 1999
#define DEFINE_ARRAY_ 2000
#define ARRAYEVAL 2001
#define ARRAYASSIGN 2002
#define ARRAY_HEAD_ 2003
#define VIEW_TRANSFORMS_NOP_ 2004
#define VIEW_TRANSFORMS_ELEMENT_ 2005
#define GET_SHOW_ 2006
#define ATTR_FUNCTION_ 2007
#define ATTR_FUNCTION_END_ 2008
#define SET_Q_FIXED_ 2009
#define SET_Q_ENERGY_ 2010
#define SET_Q_INFO_ 2011
#define SET_Q_CONSERVED_ 2012
#define KEYLOGFILE_TOGGLE_ 2013
#define ELLIPTICE 2014
#define ELLIPTICK 2015
#define INCOMPLETE_ELLIPTICF 2016
#define INCOMPLETE_ELLIPTICE 2017
#define V_VISIBILITY_DEBUG_ 2018
#define V_SCROLLBUFFERSIZE_ 2019
#define PUSH_PARAM_EXTRA_ 2020
#define PRINT_ARRAY_ 2021
#define SET_BARE_ 2022
#define GET_BARE_ 2023
#define UNSET_BARE_ 2024
#define V_PS_STRINGWIDTH_ 2025
#define V_PS_FIXEDEDGEWIDTH_ 2026
#define V_PS_TRIPLEEDGEWIDTH_ 2027
#define V_PS_CONEDGEWIDTH_ 2028
#define V_PS_BAREEDGEWIDTH_ 2029
#define V_PS_GRIDEDGEWIDTH_ 2030
#define SET_NONCONTENT_ 2031
#define UNSET_NONCONTENT_ 2032
#define GET_NONCONTENT_ 2033
#define BACKQUOTE_START_ 2034
#define BACKQUOTE_END_ 2035
#define DEFINE_EXTRA_INDEX_ 2036
#define FOR_END_ 2037
#define FOR_HEAD_ 2038
#define FOR_TOP_ 2039
#define FOR_ENTRY_ 2040
#define SET_PERM_GLOBAL_ 2041
#define SET_PERM_SGLOBAL_ 2042
#define PUSH_PERM_GLOBAL_ 2043
#define SET_PERM_PROCEDURE_ 2044
#define PUSH_PERM_GLOBAL 2045
#define PRINT_PERM_PROCEDURE_ 2046
#define SET_PERM_PROC_END_ 2047
#define DIMENSIONSET_ 2048
#define PRINT_ARRAYPART_ 2049
#define DECLARE_LOCAL_ 2050
#define FUNCTION_HEAD_ 2051
#define ARGLIST_ 2052
#define SET_FUNCTION_ 2053
#define SET_FUNC_END_ 2054
#define FUNCTION_START_ 2055
#define FUNCTION_DEF_START_ 2056
#define FUNCTION_EXIT_ 2057
#define FUNCTION_CALL_ 2058
#define FUNCTION_PROTO_START_ 2059
#define FUNCTION_PROTO_ 2060
#define SET_ARGSPROC_ 2061
#define SET_ARGSPROC_END_ 2062
#define PROCEDURE_START_ 2063
#define PROCEDURE_DEF_START_ 2064
#define PROCEDURE_EXIT_ 2065
#define PROCEDURE_CALL_ 2066
#define PROCEDURE_PROTO_START_ 2067
#define PROCEDURE_PROTO_ 2068
#define PROCEDURE_HEAD_ 2069
#define PRINT_ATTR_ARRAY_ 2070
#define PRINT_VERTEXNORMAL_ 2071
#define SIZEOF_ATTR_ 2072
#define SIZEOF_ARRAY_ 2073
#define SIZEOF_STRING_ 2074
#define BEZIER_BASIS_ 2075
#define GET_MEANCURV_ 2076
#define DEFINE_EXTRA_ 2077
#define SET_BOUNDARY_ 2078
#define GET_HIT_PARTNER_ 2079
#define SET_HIT_PARTNER_ 2080
#define UNSET_HIT_PARTNER_ 2081
#define DEFINE_QUANTITY_ 2082
#define DEFINE_METHOD_INSTANCE_ 2083
#define PUSHQFIXED_ 2084
#define PUSHQENERGY_ 2085
#define PUSHQINFO_ONLY_ 2086
#define PUSHQCONSERVED_ 2087
#define SMOOTH_GRAPH_ 2088
#define MPI_DEBUG_ 2089
#define GET_MPI_TASK_ 2090
#define POP_DISJOIN_ 2091
#define DEFINE_CONSTRAINT_ 2092
#define DEFINE_BOUNDARY_ 2093
#define V_DIFFUSION_ 2094
#define V_VERTEX_DISSOLVE_COUNT 2095
#define V_EDGE_DISSOLVE_COUNT 2096
#define V_FACET_DISSOLVE_COUNT 2097
#define V_BODY_DISSOLVE_COUNT 2098
#define V_EDGE_REFINE_COUNT 2099
#define V_FACET_REFINE_COUNT 2100
#define V_VERTEX_POP_COUNT 2101
#define V_EDGE_POP_COUNT 2102
#define V_POP_TRI_TO_EDGE_COUNT 2104
#define V_POP_EDGE_TO_TRI_COUNT 2105
#define V_POP_QUAD_TO_QUAD_COUNT 2106
#define V_EDGESWAP_COUNT 2107
#define V_T1_EDGESWAP_COUNT 2108
#define V_SKINNY_REFINE_COUNT 2109
#define V_VERTEX_DELETE_COUNT 2110
#define V_EDGE_DELETE_COUNT 2111
#define V_FACET_DELETE_COUNT 2112
#define V_BODY_DELETE_COUNT 2113
#define V_FIX_COUNT 2114
#define V_UNFIX_COUNT 2115
#define V_PS_LABELSIZE_ 2116
#define V_CPU_COUNTER 2117
#define GET_MID_EDGE_ 2118
#define GET_MID_FACET_ 2119
#define INIT_FACETEDGE_EDGE_ 2120
#define INIT_FACETEDGE_FACET_ 2121
#define NEXT_FACETEDGE_EDGE_ 2122
#define NEXT_FACETEDGE_FACET_ 2123
/* stuff transferred over from lex.h */
#define NO_TOKEN 0
#define WULFF_ 2257
#define PERIODS_ 2256
#define TORUS_ 2252
#define TORUS_FILLED_ 2251
#define SOAPFILM_ 2249
#define MOBILITY_ 2248
#define MOBILITY_TENSOR_ 2247
#define ENVECT_ 2245
#define CONVECT_ 2244
#define MERITFACTOR_ 2243
#define GRAV_CONST_ 2242
#define SPRING_CONSTANT_ 2241
#define TEMPERATURE_ 2239
#define FACES_ 2237
#define CONVEX_ 2230
#define NONNEGATIVE_ 2229
#define NONPOSITIVE_ 2228
#define PARAMETERS_ 2227
#define CONTENT_ 2222
#define BCOORD_ 2219
#define SURFACE_ENERGY_ 2216
#define SYMMETRIC_CONTENT_ 2215
#define SCALE_LIMIT_ 2214
#define CONSTRAINT_TOLERANCE_ 2211
#define ZOOM_VERTEX_ 2210
#define ZOOM_RADIUS_ 2209
#define QVECT_ 2206
#define SPACE_DIMENSION_ 2205
#define SURFACE_DIMENSION_ 2204
#define SIMPLEX_REP_ 2203
#define METRIC_ 2202
#define SYMMETRY_GROUP_ 2201
#define UNKNOWN 2199
#define CONFORMAL_ 2198
#define SQUARE_CURVATURE_ 2197
#define PARAMETER_FILE_ 2196
#define TOTAL_TIME_ 2191
#define PHASEFILE_ 2190
#define KLEIN_METRIC_ 2187
#define GLOBAL_METHOD_ 2185
#define EFIXED_ 2184
#define VIEW_TRANSFORM_GENS_ 2182
#define GAUSS_CURVATURE_ 2181
#define INSULATING_KNOT_ENERGY_ 2179
#define CONDUCTING_KNOT_ENERGY_ 2178
#define METHOD_ 2177
#define NONWALL_ 2176
#define SCALAR_INTEGRAND_ 2175
#define VECTOR_INTEGRAND_ 2174
#define FORM_INTEGRAND_ 2173
#define PARAMETER_1_ 2172
#define OPTIMIZING_PARAMETER_ 2171
#define K_VEC_ORDER_ 2170
#define LAGRANGE_ORDER_ 2169
#define HESSIAN_DOUBLE_NORMAL_ 2168
#define INTERP_BDRY_PARAM_ 2167
#define HESSIAN_NORMAL_ 2166
#define HESSIAN_NORMAL_ONE_ 2165
#define HESSIAN_NORMAL_PERP_ 2164
#define HESSIAN_SPECIAL_NORMAL_ 2163
#define LOAD_LIBRARY_ 2162
#define IGNORE_CONSTRAINTS_ 2161
#define VERSION_ 2160
#define KEEP_MACROS_ 2159
#define LAGRANGE_MULTIPLIER_ 2158
#define SWAP_COLORS_ 2157
#define STRING_TYPE_ 2156
#define IGNORE_FIXED_ 2155
#define KEEP_ORIGINALS_ 2154
#define ELEMENT_MODULUS_ 2153
#define VOLUME_METHOD_NAME_ 2152
#define DIRICHLET_MODE_ 2151
#define SOBOLEV_MODE_ 2150
#define KRAYNIKPOPVERTEX_FLAG_ 2148
#define KRAYNIKPOPEDGE_FLAG_ 2147
#define VERSIONTOKEN_ 2146
#define HESSIAN_SPECIAL_NORMAL_VECTOR_ 2145
#define RGB_COLORS_FLAG_ 2144
#define CIRCULAR_ARC_DRAW_ 2143
#define VISIBILITY_TEST_ 2142
#define SPARSE_CONSTRAINTS_ 2141
#define BLAS_FLAG_ 2140
#define AUGMENTED_HESSIAN_ 2139
#define AREA_METHOD_NAME_ 2138
#define LENGTH_METHOD_NAME_ 2137
#define BREAK_AFTER_WARNING_ 2136
#define PARTNER_HITTING_ 2135
#define DISPLAY_PERIODS_ 2132
/* end stuff transferred over from lex.h */
#define FULL_BOUNDING_BOX_ 2258
#define LIST_CONSTRAINT_ 2259
#define LIST_BOUNDARY_ 2260
#define LIST_QUANTITY_ 2261
#define LIST_METHOD_INSTANCE_ 2262
#define INIT_EDGE_FACETEDGE_ 2263
#define NEXT_EDGE_FACETEDGE_ 2264
#define POP_TO_FACE_ 2265
#define POP_TO_EDGE_ 2266
#define LINE_CONTINUATION 2267
#define V_MINDEG_DEBUG_LEVEL 2268
#define V_MINDEG_MARGIN 2269
#define V_MINDEG_MIN_REGION_SIZE 2270
#define SET_ELEMENT_GLOBAL_ 2271
#define SINGLE_ELEMENT_EXPR_ 2272
#define UNPUTTED_ 2273
/* for BREAK and CONTINUE */
extern int loopdepth;
/* tree node for expression trees */
struct treenode
{
int type; /* type of node */
int left; /* left subexpression index offset */
int right; /* right subexpression index offset */
int line_no; /* line number of source file */
int file_no; /* number of source file */
int datatype; /* type of expression value */
int flags;
union { int intval; /* misc. integer data */
int skipsize; /* nodes to skip over */
int indexcount; /* number of indices */
int argcount; /* number of function arguments */
int assigntype; /* for assignments */
int aggrtype; /* aggregate type */
int eltype; /* element type */
int maxsteps; /* for burchard() */
int coordnum;
REAL real; /* constant value */
struct sym *symptr; /* symbol table ptrs */
int localnum; /* where element id stored*/
int extranum; /* number of extra attr */
element_id id; /* element id */
int name_id; /* name identifier */
int letter; /* for redefine */
int quant_id; /* named quantity id */
int meth_id; /* named method id */
int con_id; /* number of constraint */
int bdry_id; /* number of boundary */
int toggle_id;
int toggle_state; /* ON_ or OFF_ */
int bool_val; /* 0 or 1 */
int intpow; /* integer power */
int wherecount;
int userfunc;
char *string; /* string value */
struct expnode enode; /* for expression */
dll_func_type funcptr; /* DLL function */
} op1; /* operand 1*/
union { int intval; /* misc. integer data */
int eltype; /* element type */
int valtype; /* data type */
int breakdepth; /* number of loop to break out of */
struct sym *symptr; /* symbol table ptrs */
char *string;
int localnum; /* where loop element id stored*/
int coordnum;
int attr_kind;
int extranum; /* number of extra attr */
int jumpsize;
int assigntype;
int argcount;
int indexcount;
int name_id;
int quant_id;
int meth_id;
} op2; /* operand 2 */
union { int intval[2]; /* misc. integer data */
int breakjump;
int argcount;
int argtype;
int extra_info; /* extra attr eltype and number */
int extranum;
int connum; /* constraint number */
int bdrynum;
int name_id;
int localnum; /* where element id stored*/
} op3;
union { int contjump;
int argtype;
int extranum;
int ret_type;
int eltype; /* element type */
int name_id;
} op4;
union { struct sym *symptr; /* symbol table ptrs */
char *string;
struct locallist_t *locals; /* for procedures */
} op5;
int stack_delta; /* what node does to runtime stack */
#ifdef _DEBUG
int stack_spot; /* where stack should be after evaluation
of this node. */
#endif
int stackpos; /* local variable on stack for storing stack
position for chopping stack after break or continue */
};
/* flags, also used for expnode */
#define LOCAL_VAR_REF 4
#define LOCAL_VAR_REF_2 8
#define LOCAL_VAR_REF_3 0x10
#define HAS_STRING 0x20
#define EPHEMERAL 0x40 /* refers to a nonpermanent name */
#define PERMNODE 0x80 /* part of permanent command */
#define HAS_LOCALLIST 0x100
#define HAS_STRING_5 0x200
#define DEALLOCATE_POINTER 0x400
#define IN_ELEMENT_LOOP 0x800
#define BREAKPOINT_NODE 0x1000
#define IS_RVALUE 0x2000
#define SET_ASSIGNOP 0x4000
#define RECALC_NODE 0x8000
#define IS_VIRTUAL_ATTR 0x10000
/* for some bit packing */
#define ESHIFT 12
/* for some type and number packing */
#define YYTYPESHIFT 25
#define YYSHIFTMASK (((1<