Code/Resource
Windows Develop
Linux-Unix program
Internet-Socket-Network
Web Server
Browser Client
Ftp Server
Ftp Client
Browser Plugins
Proxy Server
Email Server
Email Client
WEB Mail
Firewall-Security
Telnet Server
Telnet Client
ICQ-IM-Chat
Search Engine
Sniffer Package capture
Remote Control
xml-soap-webservice
P2P
WEB(ASP,PHP,...)
TCP/IP Stack
SNMP
Grid Computing
SilverLight
DNS
Cluster Service
Network Security
Communication-Mobile
Game Program
Editor
Multimedia program
Graph program
Compiler program
Compress-Decompress algrithms
Crypt_Decrypt algrithms
Mathimatics-Numerical algorithms
MultiLanguage
Disk/Storage
Java Develop
assembly language
Applications
Other systems
Database system
Embeded-SCM Develop
FlashMX/Flex
source in ebook
Delphi VCL
OS Develop
MiddleWare
MPI
MacOS develop
LabView
ELanguage
Software/Tools
E-Books
Artical/Document
triangle.c
Package: triangle.zip [view]
Upload User: yflamps
Upload Date: 2010-04-01
Package Size: 155k
Code Size: 636k
Category:
3D Graphic
Development Platform:
C/C++
- /*****************************************************************************/
- /* */
- /* 888888888 ,o, / 888 */
- /* 888 88o88o " o8888o 88o8888o o88888o 888 o88888o */
- /* 888 888 888 88b 888 888 888 888 888 d888 88b */
- /* 888 888 888 o88^o888 888 888 "88888" 888 8888oo888 */
- /* 888 888 888 C888 888 888 888 / 888 q888 */
- /* 888 888 888 "88o^888 888 888 Cb 888 "88oooo" */
- /* "8oo8D */
- /* */
- /* A Two-Dimensional Quality Mesh Generator and Delaunay Triangulator. */
- /* (triangle.c) */
- /* */
- /* Version 1.6 */
- /* July 28, 2005 */
- /* */
- /* Copyright 1993, 1995, 1997, 1998, 2002, 2005 */
- /* Jonathan Richard Shewchuk */
- /* 2360 Woolsey #H */
- /* Berkeley, California 94705-1927 */
- /* jrs@cs.berkeley.edu */
- /* */
- /* This program may be freely redistributed under the condition that the */
- /* copyright notices (including this entire header and the copyright */
- /* notice printed when the `-h' switch is selected) are not removed, and */
- /* no compensation is received. Private, research, and institutional */
- /* use is free. You may distribute modified versions of this code UNDER */
- /* THE CONDITION THAT THIS CODE AND ANY MODIFICATIONS MADE TO IT IN THE */
- /* SAME FILE REMAIN UNDER COPYRIGHT OF THE ORIGINAL AUTHOR, BOTH SOURCE */
- /* AND OBJECT CODE ARE MADE FREELY AVAILABLE WITHOUT CHARGE, AND CLEAR */
- /* NOTICE IS GIVEN OF THE MODIFICATIONS. Distribution of this code as */
- /* part of a commercial system is permissible ONLY BY DIRECT ARRANGEMENT */
- /* WITH THE AUTHOR. (If you are not directly supplying this code to a */
- /* customer, and you are instead telling them how they can obtain it for */
- /* free, then you are not required to make any arrangement with me.) */
- /* */
- /* Hypertext instructions for Triangle are available on the Web at */
- /* */
- /* http://www.cs.cmu.edu/~quake/triangle.html */
- /* */
- /* Disclaimer: Neither I nor Carnegie Mellon warrant this code in any way */
- /* whatsoever. This code is provided "as-is". Use at your own risk. */
- /* */
- /* Some of the references listed below are marked with an asterisk. [*] */
- /* These references are available for downloading from the Web page */
- /* */
- /* http://www.cs.cmu.edu/~quake/triangle.research.html */
- /* */
- /* Three papers discussing aspects of Triangle are available. A short */
- /* overview appears in "Triangle: Engineering a 2D Quality Mesh */
- /* Generator and Delaunay Triangulator," in Applied Computational */
- /* Geometry: Towards Geometric Engineering, Ming C. Lin and Dinesh */
- /* Manocha, editors, Lecture Notes in Computer Science volume 1148, */
- /* pages 203-222, Springer-Verlag, Berlin, May 1996 (from the First ACM */
- /* Workshop on Applied Computational Geometry). [*] */
- /* */
- /* The algorithms are discussed in the greatest detail in "Delaunay */
- /* Refinement Algorithms for Triangular Mesh Generation," Computational */
- /* Geometry: Theory and Applications 22(1-3):21-74, May 2002. [*] */
- /* */
- /* More detail about the data structures may be found in my dissertation: */
- /* "Delaunay Refinement Mesh Generation," Ph.D. thesis, Technical Report */
- /* CMU-CS-97-137, School of Computer Science, Carnegie Mellon University, */
- /* Pittsburgh, Pennsylvania, 18 May 1997. [*] */
- /* */
- /* Triangle was created as part of the Quake Project in the School of */
- /* Computer Science at Carnegie Mellon University. For further */
- /* information, see Hesheng Bao, Jacobo Bielak, Omar Ghattas, Loukas F. */
- /* Kallivokas, David R. O'Hallaron, Jonathan R. Shewchuk, and Jifeng Xu, */
- /* "Large-scale Simulation of Elastic Wave Propagation in Heterogeneous */
- /* Media on Parallel Computers," Computer Methods in Applied Mechanics */
- /* and Engineering 152(1-2):85-102, 22 January 1998. */
- /* */
- /* Triangle's Delaunay refinement algorithm for quality mesh generation is */
- /* a hybrid of one due to Jim Ruppert, "A Delaunay Refinement Algorithm */
- /* for Quality 2-Dimensional Mesh Generation," Journal of Algorithms */
- /* 18(3):548-585, May 1995 [*], and one due to L. Paul Chew, "Guaranteed- */
- /* Quality Mesh Generation for Curved Surfaces," Proceedings of the Ninth */
- /* Annual Symposium on Computational Geometry (San Diego, California), */
- /* pages 274-280, Association for Computing Machinery, May 1993, */
- /* http://portal.acm.org/citation.cfm?id=161150 . */
- /* */
- /* The Delaunay refinement algorithm has been modified so that it meshes */
- /* domains with small input angles well, as described in Gary L. Miller, */
- /* Steven E. Pav, and Noel J. Walkington, "When and Why Ruppert's */
- /* Algorithm Works," Twelfth International Meshing Roundtable, pages */
- /* 91-102, Sandia National Laboratories, September 2003. [*] */
- /* */
- /* My implementation of the divide-and-conquer and incremental Delaunay */
- /* triangulation algorithms follows closely the presentation of Guibas */
- /* and Stolfi, even though I use a triangle-based data structure instead */
- /* of their quad-edge data structure. (In fact, I originally implemented */
- /* Triangle using the quad-edge data structure, but the switch to a */
- /* triangle-based data structure sped Triangle by a factor of two.) The */
- /* mesh manipulation primitives and the two aforementioned Delaunay */
- /* triangulation algorithms are described by Leonidas J. Guibas and Jorge */
- /* Stolfi, "Primitives for the Manipulation of General Subdivisions and */
- /* the Computation of Voronoi Diagrams," ACM Transactions on Graphics */
- /* 4(2):74-123, April 1985, http://portal.acm.org/citation.cfm?id=282923 .*/
- /* */
- /* Their O(n log n) divide-and-conquer algorithm is adapted from Der-Tsai */
- /* Lee and Bruce J. Schachter, "Two Algorithms for Constructing the */
- /* Delaunay Triangulation," International Journal of Computer and */
- /* Information Science 9(3):219-242, 1980. Triangle's improvement of the */
- /* divide-and-conquer algorithm by alternating between vertical and */
- /* horizontal cuts was introduced by Rex A. Dwyer, "A Faster Divide-and- */
- /* Conquer Algorithm for Constructing Delaunay Triangulations," */
- /* Algorithmica 2(2):137-151, 1987. */
- /* */
- /* The incremental insertion algorithm was first proposed by C. L. Lawson, */
- /* "Software for C1 Surface Interpolation," in Mathematical Software III, */
- /* John R. Rice, editor, Academic Press, New York, pp. 161-194, 1977. */
- /* For point location, I use the algorithm of Ernst P. Mucke, Isaac */
- /* Saias, and Binhai Zhu, "Fast Randomized Point Location Without */
- /* Preprocessing in Two- and Three-Dimensional Delaunay Triangulations," */
- /* Proceedings of the Twelfth Annual Symposium on Computational Geometry, */
- /* ACM, May 1996. [*] If I were to randomize the order of vertex */
- /* insertion (I currently don't bother), their result combined with the */
- /* result of Kenneth L. Clarkson and Peter W. Shor, "Applications of */
- /* Random Sampling in Computational Geometry II," Discrete & */
- /* Computational Geometry 4(1):387-421, 1989, would yield an expected */
- /* O(n^{4/3}) bound on running time. */
- /* */
- /* The O(n log n) sweepline Delaunay triangulation algorithm is taken from */
- /* Steven Fortune, "A Sweepline Algorithm for Voronoi Diagrams", */
- /* Algorithmica 2(2):153-174, 1987. A random sample of edges on the */
- /* boundary of the triangulation are maintained in a splay tree for the */
- /* purpose of point location. Splay trees are described by Daniel */
- /* Dominic Sleator and Robert Endre Tarjan, "Self-Adjusting Binary Search */
- /* Trees," Journal of the ACM 32(3):652-686, July 1985, */
- /* http://portal.acm.org/citation.cfm?id=3835 . */
- /* */
- /* The algorithms for exact computation of the signs of determinants are */
- /* described in Jonathan Richard Shewchuk, "Adaptive Precision Floating- */
- /* Point Arithmetic and Fast Robust Geometric Predicates," Discrete & */
- /* Computational Geometry 18(3):305-363, October 1997. (Also available */
- /* as Technical Report CMU-CS-96-140, School of Computer Science, */
- /* Carnegie Mellon University, Pittsburgh, Pennsylvania, May 1996.) [*] */
- /* An abbreviated version appears as Jonathan Richard Shewchuk, "Robust */
- /* Adaptive Floating-Point Geometric Predicates," Proceedings of the */
- /* Twelfth Annual Symposium on Computational Geometry, ACM, May 1996. [*] */
- /* Many of the ideas for my exact arithmetic routines originate with */
- /* Douglas M. Priest, "Algorithms for Arbitrary Precision Floating Point */
- /* Arithmetic," Tenth Symposium on Computer Arithmetic, pp. 132-143, IEEE */
- /* Computer Society Press, 1991. [*] Many of the ideas for the correct */
- /* evaluation of the signs of determinants are taken from Steven Fortune */
- /* and Christopher J. Van Wyk, "Efficient Exact Arithmetic for Computa- */
- /* tional Geometry," Proceedings of the Ninth Annual Symposium on */
- /* Computational Geometry, ACM, pp. 163-172, May 1993, and from Steven */
- /* Fortune, "Numerical Stability of Algorithms for 2D Delaunay Triangu- */
- /* lations," International Journal of Computational Geometry & Applica- */
- /* tions 5(1-2):193-213, March-June 1995. */
- /* */
- /* The method of inserting new vertices off-center (not precisely at the */
- /* circumcenter of every poor-quality triangle) is from Alper Ungor, */
- /* "Off-centers: A New Type of Steiner Points for Computing Size-Optimal */
- /* Quality-Guaranteed Delaunay Triangulations," Proceedings of LATIN */
- /* 2004 (Buenos Aires, Argentina), April 2004. */
- /* */
- /* For definitions of and results involving Delaunay triangulations, */
- /* constrained and conforming versions thereof, and other aspects of */
- /* triangular mesh generation, see the excellent survey by Marshall Bern */
- /* and David Eppstein, "Mesh Generation and Optimal Triangulation," in */
- /* Computing and Euclidean Geometry, Ding-Zhu Du and Frank Hwang, */
- /* editors, World Scientific, Singapore, pp. 23-90, 1992. [*] */
- /* */
- /* The time for incrementally adding PSLG (planar straight line graph) */
- /* segments to create a constrained Delaunay triangulation is probably */
- /* O(t^2) per segment in the worst case and O(t) per segment in the */
- /* common case, where t is the number of triangles that intersect the */
- /* segment before it is inserted. This doesn't count point location, */
- /* which can be much more expensive. I could improve this to O(d log d) */
- /* time, but d is usually quite small, so it's not worth the bother. */
- /* (This note does not apply when the -s switch is used, invoking a */
- /* different method is used to insert segments.) */
- /* */
- /* The time for deleting a vertex from a Delaunay triangulation is O(d^2) */
- /* in the worst case and O(d) in the common case, where d is the degree */
- /* of the vertex being deleted. I could improve this to O(d log d) time, */
- /* but d is usually quite small, so it's not worth the bother. */
- /* */
- /* Ruppert's Delaunay refinement algorithm typically generates triangles */
- /* at a linear rate (constant time per triangle) after the initial */
- /* triangulation is formed. There may be pathological cases where */
- /* quadratic time is required, but these never arise in practice. */
- /* */
- /* The geometric predicates (circumcenter calculations, segment */
- /* intersection formulae, etc.) appear in my "Lecture Notes on Geometric */
- /* Robustness" at http://www.cs.berkeley.edu/~jrs/mesh . */
- /* */
- /* If you make any improvements to this code, please please please let me */
- /* know, so that I may obtain the improvements. Even if you don't change */
- /* the code, I'd still love to hear what it's being used for. */
- /* */
- /*****************************************************************************/
- /* For single precision (which will save some memory and reduce paging), */
- /* define the symbol SINGLE by using the -DSINGLE compiler switch or by */
- /* writing "#define SINGLE" below. */
- /* */
- /* For double precision (which will allow you to refine meshes to a smaller */
- /* edge length), leave SINGLE undefined. */
- /* */
- /* Double precision uses more memory, but improves the resolution of the */
- /* meshes you can generate with Triangle. It also reduces the likelihood */
- /* of a floating exception due to overflow. Finally, it is much faster */
- /* than single precision on 64-bit architectures like the DEC Alpha. I */
- /* recommend double precision unless you want to generate a mesh for which */
- /* you do not have enough memory. */
- /* #define SINGLE */
- #ifdef SINGLE
- #define REAL float
- #else /* not SINGLE */
- #define REAL double
- #endif /* not SINGLE */
- /* If yours is not a Unix system, define the NO_TIMER compiler switch to */
- /* remove the Unix-specific timing code. */
- /* #define NO_TIMER */
- /* To insert lots of self-checks for internal errors, define the SELF_CHECK */
- /* symbol. This will slow down the program significantly. It is best to */
- /* define the symbol using the -DSELF_CHECK compiler switch, but you could */
- /* write "#define SELF_CHECK" below. If you are modifying this code, I */
- /* recommend you turn self-checks on until your work is debugged. */
- /* #define SELF_CHECK */
- /* To compile Triangle as a callable object library (triangle.o), define the */
- /* TRILIBRARY symbol. Read the file triangle.h for details on how to call */
- /* the procedure triangulate() that results. */
- /* #define TRILIBRARY */
- /* It is possible to generate a smaller version of Triangle using one or */
- /* both of the following symbols. Define the REDUCED symbol to eliminate */
- /* all features that are primarily of research interest; specifically, the */
- /* -i, -F, -s, and -C switches. Define the CDT_ONLY symbol to eliminate */
- /* all meshing algorithms above and beyond constrained Delaunay */
- /* triangulation; specifically, the -r, -q, -a, -u, -D, -S, and -s */
- /* switches. These reductions are most likely to be useful when */
- /* generating an object library (triangle.o) by defining the TRILIBRARY */
- /* symbol. */
- /* #define REDUCED */
- /* #define CDT_ONLY */
- /* On some machines, my exact arithmetic routines might be defeated by the */
- /* use of internal extended precision floating-point registers. The best */
- /* way to solve this problem is to set the floating-point registers to use */
- /* single or double precision internally. On 80x86 processors, this may */
- /* be accomplished by setting the CPU86 symbol for the Microsoft C */
- /* compiler, or the LINUX symbol for the gcc compiler running on Linux. */
- /* */
- /* An inferior solution is to declare certain values as `volatile', thus */
- /* forcing them to be stored to memory and rounded off. Unfortunately, */
- /* this solution might slow Triangle down quite a bit. To use volatile */
- /* values, write "#define INEXACT volatile" below. Normally, however, */
- /* INEXACT should be defined to be nothing. ("#define INEXACT".) */
- /* */
- /* For more discussion, see http://www.cs.cmu.edu/~quake/robust.pc.html . */
- /* For yet more discussion, see Section 5 of my paper, "Adaptive Precision */
- /* Floating-Point Arithmetic and Fast Robust Geometric Predicates" (also */
- /* available as Section 6.6 of my dissertation). */
- /* #define CPU86 */
- /* #define LINUX */
- #define INEXACT /* Nothing */
- /* #define INEXACT volatile */
- /* Maximum number of characters in a file name (including the null). */
- #define FILENAMESIZE 2048
- /* Maximum number of characters in a line read from a file (including the */
- /* null). */
- #define INPUTLINESIZE 1024
- /* For efficiency, a variety of data structures are allocated in bulk. The */
- /* following constants determine how many of each structure is allocated */
- /* at once. */
- #define TRIPERBLOCK 4092 /* Number of triangles allocated at once. */
- #define SUBSEGPERBLOCK 508 /* Number of subsegments allocated at once. */
- #define VERTEXPERBLOCK 4092 /* Number of vertices allocated at once. */
- #define VIRUSPERBLOCK 1020 /* Number of virus triangles allocated at once. */
- /* Number of encroached subsegments allocated at once. */
- #define BADSUBSEGPERBLOCK 252
- /* Number of skinny triangles allocated at once. */
- #define BADTRIPERBLOCK 4092
- /* Number of flipped triangles allocated at once. */
- #define FLIPSTACKERPERBLOCK 252
- /* Number of splay tree nodes allocated at once. */
- #define SPLAYNODEPERBLOCK 508
- /* The vertex types. A DEADVERTEX has been deleted entirely. An */
- /* UNDEADVERTEX is not part of the mesh, but is written to the output */
- /* .node file and affects the node indexing in the other output files. */
- #define INPUTVERTEX 0
- #define SEGMENTVERTEX 1
- #define FREEVERTEX 2
- #define DEADVERTEX -32768
- #define UNDEADVERTEX -32767
- /* The next line is used to outsmart some very stupid compilers. If your */
- /* compiler is smarter, feel free to replace the "int" with "void". */
- /* Not that it matters. */
- #define VOID int
- /* Two constants for algorithms based on random sampling. Both constants */
- /* have been chosen empirically to optimize their respective algorithms. */
- /* Used for the point location scheme of Mucke, Saias, and Zhu, to decide */
- /* how large a random sample of triangles to inspect. */
- #define SAMPLEFACTOR 11
- /* Used in Fortune's sweepline Delaunay algorithm to determine what fraction */
- /* of boundary edges should be maintained in the splay tree for point */
- /* location on the front. */
- #define SAMPLERATE 10
- /* A number that speaks for itself, every kissable digit. */
- #define PI 3.141592653589793238462643383279502884197169399375105820974944592308
- /* Another fave. */
- #define SQUAREROOTTWO 1.4142135623730950488016887242096980785696718753769480732
- /* And here's one for those of you who are intimidated by math. */
- #define ONETHIRD 0.333333333333333333333333333333333333333333333333333333333333
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <math.h>
- #ifndef NO_TIMER
- #include <sys/time.h>
- #endif /* not NO_TIMER */
- #ifdef CPU86
- #include <float.h>
- #endif /* CPU86 */
- #ifdef LINUX
- #include <fpu_control.h>
- #endif /* LINUX */
- #ifdef TRILIBRARY
- #include "triangle.h"
- #endif /* TRILIBRARY */
- /* A few forward declarations. */
- #ifndef TRILIBRARY
- char *readline();
- char *findfield();
- #endif /* not TRILIBRARY */
- /* Labels that signify the result of point location. The result of a */
- /* search indicates that the point falls in the interior of a triangle, on */
- /* an edge, on a vertex, or outside the mesh. */
- enum locateresult {INTRIANGLE, ONEDGE, ONVERTEX, OUTSIDE};
- /* Labels that signify the result of vertex insertion. The result indicates */
- /* that the vertex was inserted with complete success, was inserted but */
- /* encroaches upon a subsegment, was not inserted because it lies on a */
- /* segment, or was not inserted because another vertex occupies the same */
- /* location. */
- enum insertvertexresult {SUCCESSFULVERTEX, ENCROACHINGVERTEX, VIOLATINGVERTEX,
- DUPLICATEVERTEX};
- /* Labels that signify the result of direction finding. The result */
- /* indicates that a segment connecting the two query points falls within */
- /* the direction triangle, along the left edge of the direction triangle, */
- /* or along the right edge of the direction triangle. */
- enum finddirectionresult {WITHIN, LEFTCOLLINEAR, RIGHTCOLLINEAR};
- /*****************************************************************************/
- /* */
- /* The basic mesh data structures */
- /* */
- /* There are three: vertices, triangles, and subsegments (abbreviated */
- /* `subseg'). These three data structures, linked by pointers, comprise */
- /* the mesh. A vertex simply represents a mesh vertex and its properties. */
- /* A triangle is a triangle. A subsegment is a special data structure used */
- /* to represent an impenetrable edge of the mesh (perhaps on the outer */
- /* boundary, on the boundary of a hole, or part of an internal boundary */
- /* separating two triangulated regions). Subsegments represent boundaries, */
- /* defined by the user, that triangles may not lie across. */
- /* */
- /* A triangle consists of a list of three vertices, a list of three */
- /* adjoining triangles, a list of three adjoining subsegments (when */
- /* segments exist), an arbitrary number of optional user-defined */
- /* floating-point attributes, and an optional area constraint. The latter */
- /* is an upper bound on the permissible area of each triangle in a region, */
- /* used for mesh refinement. */
- /* */
- /* For a triangle on a boundary of the mesh, some or all of the neighboring */
- /* triangles may not be present. For a triangle in the interior of the */
- /* mesh, often no neighboring subsegments are present. Such absent */
- /* triangles and subsegments are never represented by NULL pointers; they */
- /* are represented by two special records: `dummytri', the triangle that */
- /* fills "outer space", and `dummysub', the omnipresent subsegment. */
- /* `dummytri' and `dummysub' are used for several reasons; for instance, */
- /* they can be dereferenced and their contents examined without violating */
- /* protected memory. */
- /* */
- /* However, it is important to understand that a triangle includes other */
- /* information as well. The pointers to adjoining vertices, triangles, and */
- /* subsegments are ordered in a way that indicates their geometric relation */
- /* to each other. Furthermore, each of these pointers contains orientation */
- /* information. Each pointer to an adjoining triangle indicates which face */
- /* of that triangle is contacted. Similarly, each pointer to an adjoining */
- /* subsegment indicates which side of that subsegment is contacted, and how */
- /* the subsegment is oriented relative to the triangle. */
- /* */
- /* The data structure representing a subsegment may be thought to be */
- /* abutting the edge of one or two triangle data structures: either */
- /* sandwiched between two triangles, or resting against one triangle on an */
- /* exterior boundary or hole boundary. */
- /* */
- /* A subsegment consists of a list of four vertices--the vertices of the */
- /* subsegment, and the vertices of the segment it is a part of--a list of */
- /* two adjoining subsegments, and a list of two adjoining triangles. One */
- /* of the two adjoining triangles may not be present (though there should */
- /* always be one), and neighboring subsegments might not be present. */
- /* Subsegments also store a user-defined integer "boundary marker". */
- /* Typically, this integer is used to indicate what boundary conditions are */
- /* to be applied at that location in a finite element simulation. */
- /* */
- /* Like triangles, subsegments maintain information about the relative */
- /* orientation of neighboring objects. */
- /* */
- /* Vertices are relatively simple. A vertex is a list of floating-point */
- /* numbers, starting with the x, and y coordinates, followed by an */
- /* arbitrary number of optional user-defined floating-point attributes, */
- /* followed by an integer boundary marker. During the segment insertion */
- /* phase, there is also a pointer from each vertex to a triangle that may */
- /* contain it. Each pointer is not always correct, but when one is, it */
- /* speeds up segment insertion. These pointers are assigned values once */
- /* at the beginning of the segment insertion phase, and are not used or */
- /* updated except during this phase. Edge flipping during segment */
- /* insertion will render some of them incorrect. Hence, don't rely upon */
- /* them for anything. */
- /* */
- /* Other than the exception mentioned above, vertices have no information */
- /* about what triangles, subfacets, or subsegments they are linked to. */
- /* */
- /*****************************************************************************/
- /*****************************************************************************/
- /* */
- /* Handles */
- /* */
- /* The oriented triangle (`otri') and oriented subsegment (`osub') data */
- /* structures defined below do not themselves store any part of the mesh. */
- /* The mesh itself is made of `triangle's, `subseg's, and `vertex's. */
- /* */
- /* Oriented triangles and oriented subsegments will usually be referred to */
- /* as "handles." A handle is essentially a pointer into the mesh; it */
- /* allows you to "hold" one particular part of the mesh. Handles are used */
- /* to specify the regions in which one is traversing and modifying the mesh.*/
- /* A single `triangle' may be held by many handles, or none at all. (The */
- /* latter case is not a memory leak, because the triangle is still */
- /* connected to other triangles in the mesh.) */
- /* */
- /* An `otri' is a handle that holds a triangle. It holds a specific edge */
- /* of the triangle. An `osub' is a handle that holds a subsegment. It */
- /* holds either the left or right side of the subsegment. */
- /* */
- /* Navigation about the mesh is accomplished through a set of mesh */
- /* manipulation primitives, further below. Many of these primitives take */
- /* a handle and produce a new handle that holds the mesh near the first */
- /* handle. Other primitives take two handles and glue the corresponding */
- /* parts of the mesh together. The orientation of the handles is */
- /* important. For instance, when two triangles are glued together by the */
- /* bond() primitive, they are glued at the edges on which the handles lie. */
- /* */
- /* Because vertices have no information about which triangles they are */
- /* attached to, I commonly represent a vertex by use of a handle whose */
- /* origin is the vertex. A single handle can simultaneously represent a */
- /* triangle, an edge, and a vertex. */
- /* */
- /*****************************************************************************/
- /* The triangle data structure. Each triangle contains three pointers to */
- /* adjoining triangles, plus three pointers to vertices, plus three */
- /* pointers to subsegments (declared below; these pointers are usually */
- /* `dummysub'). It may or may not also contain user-defined attributes */
- /* and/or a floating-point "area constraint." It may also contain extra */
- /* pointers for nodes, when the user asks for high-order elements. */
- /* Because the size and structure of a `triangle' is not decided until */
- /* runtime, I haven't simply declared the type `triangle' as a struct. */
- typedef REAL **triangle; /* Really: typedef triangle *triangle */
- /* An oriented triangle: includes a pointer to a triangle and orientation. */
- /* The orientation denotes an edge of the triangle. Hence, there are */
- /* three possible orientations. By convention, each edge always points */
- /* counterclockwise about the corresponding triangle. */
- struct otri {
- triangle *tri;
- int orient; /* Ranges from 0 to 2. */
- };
- /* The subsegment data structure. Each subsegment contains two pointers to */
- /* adjoining subsegments, plus four pointers to vertices, plus two */
- /* pointers to adjoining triangles, plus one boundary marker, plus one */
- /* segment number. */
- typedef REAL **subseg; /* Really: typedef subseg *subseg */
- /* An oriented subsegment: includes a pointer to a subsegment and an */
- /* orientation. The orientation denotes a side of the edge. Hence, there */
- /* are two possible orientations. By convention, the edge is always */
- /* directed so that the "side" denoted is the right side of the edge. */
- struct osub {
- subseg *ss;
- int ssorient; /* Ranges from 0 to 1. */
- };
- /* The vertex data structure. Each vertex is actually an array of REALs. */
- /* The number of REALs is unknown until runtime. An integer boundary */
- /* marker, and sometimes a pointer to a triangle, is appended after the */
- /* REALs. */
- typedef REAL *vertex;
- /* A queue used to store encroached subsegments. Each subsegment's vertices */
- /* are stored so that we can check whether a subsegment is still the same. */
- struct badsubseg {
- subseg encsubseg; /* An encroached subsegment. */
- vertex subsegorg, subsegdest; /* Its two vertices. */
- };
- /* A queue used to store bad triangles. The key is the square of the cosine */
- /* of the smallest angle of the triangle. Each triangle's vertices are */
- /* stored so that one can check whether a triangle is still the same. */
- struct badtriang {
- triangle poortri; /* A skinny or too-large triangle. */
- REAL key; /* cos^2 of smallest (apical) angle. */
- vertex triangorg, triangdest, triangapex; /* Its three vertices. */
- struct badtriang *nexttriang; /* Pointer to next bad triangle. */
- };
- /* A stack of triangles flipped during the most recent vertex insertion. */
- /* The stack is used to undo the vertex insertion if the vertex encroaches */
- /* upon a subsegment. */
- struct flipstacker {
- triangle flippedtri; /* A recently flipped triangle. */
- struct flipstacker *prevflip; /* Previous flip in the stack. */
- };
- /* A node in a heap used to store events for the sweepline Delaunay */
- /* algorithm. Nodes do not point directly to their parents or children in */
- /* the heap. Instead, each node knows its position in the heap, and can */
- /* look up its parent and children in a separate array. The `eventptr' */
- /* points either to a `vertex' or to a triangle (in encoded format, so */
- /* that an orientation is included). In the latter case, the origin of */
- /* the oriented triangle is the apex of a "circle event" of the sweepline */
- /* algorithm. To distinguish site events from circle events, all circle */
- /* events are given an invalid (smaller than `xmin') x-coordinate `xkey'. */
- struct event {
- REAL xkey, ykey; /* Coordinates of the event. */
- VOID *eventptr; /* Can be a vertex or the location of a circle event. */
- int heapposition; /* Marks this event's position in the heap. */
- };
- /* A node in the splay tree. Each node holds an oriented ghost triangle */
- /* that represents a boundary edge of the growing triangulation. When a */
- /* circle event covers two boundary edges with a triangle, so that they */
- /* are no longer boundary edges, those edges are not immediately deleted */
- /* from the tree; rather, they are lazily deleted when they are next */
- /* encountered. (Since only a random sample of boundary edges are kept */
- /* in the tree, lazy deletion is faster.) `keydest' is used to verify */
- /* that a triangle is still the same as when it entered the splay tree; if */
- /* it has been rotated (due to a circle event), it no longer represents a */
- /* boundary edge and should be deleted. */
- struct splaynode {
- struct otri keyedge; /* Lprev of an edge on the front. */
- vertex keydest; /* Used to verify that splay node is still live. */
- struct splaynode *lchild, *rchild; /* Children in splay tree. */
- };
- /* A type used to allocate memory. firstblock is the first block of items. */
- /* nowblock is the block from which items are currently being allocated. */
- /* nextitem points to the next slab of free memory for an item. */
- /* deaditemstack is the head of a linked list (stack) of deallocated items */
- /* that can be recycled. unallocateditems is the number of items that */
- /* remain to be allocated from nowblock. */
- /* */
- /* Traversal is the process of walking through the entire list of items, and */
- /* is separate from allocation. Note that a traversal will visit items on */
- /* the "deaditemstack" stack as well as live items. pathblock points to */
- /* the block currently being traversed. pathitem points to the next item */
- /* to be traversed. pathitemsleft is the number of items that remain to */
- /* be traversed in pathblock. */
- /* */
- /* alignbytes determines how new records should be aligned in memory. */
- /* itembytes is the length of a record in bytes (after rounding up). */
- /* itemsperblock is the number of items allocated at once in a single */
- /* block. itemsfirstblock is the number of items in the first block, */
- /* which can vary from the others. items is the number of currently */
- /* allocated items. maxitems is the maximum number of items that have */
- /* been allocated at once; it is the current number of items plus the */
- /* number of records kept on deaditemstack. */
- struct memorypool {
- VOID **firstblock, **nowblock;
- VOID *nextitem;
- VOID *deaditemstack;
- VOID **pathblock;
- VOID *pathitem;
- int alignbytes;
- int itembytes;
- int itemsperblock;
- int itemsfirstblock;
- long items, maxitems;
- int unallocateditems;
- int pathitemsleft;
- };
- /* Global constants. */
- REAL splitter; /* Used to split REAL factors for exact multiplication. */
- REAL epsilon; /* Floating-point machine epsilon. */
- REAL resulterrbound;
- REAL ccwerrboundA, ccwerrboundB, ccwerrboundC;
- REAL iccerrboundA, iccerrboundB, iccerrboundC;
- REAL o3derrboundA, o3derrboundB, o3derrboundC;
- /* Random number seed is not constant, but I've made it global anyway. */
- unsigned long randomseed; /* Current random number seed. */
- /* Mesh data structure. Triangle operates on only one mesh, but the mesh */
- /* structure is used (instead of global variables) to allow reentrancy. */
- struct mesh {
- /* Variables used to allocate memory for triangles, subsegments, vertices, */
- /* viri (triangles being eaten), encroached segments, bad (skinny or too */
- /* large) triangles, and splay tree nodes. */
- struct memorypool triangles;
- struct memorypool subsegs;
- struct memorypool vertices;
- struct memorypool viri;
- struct memorypool badsubsegs;
- struct memorypool badtriangles;
- struct memorypool flipstackers;
- struct memorypool splaynodes;
- /* Variables that maintain the bad triangle queues. The queues are */
- /* ordered from 4095 (highest priority) to 0 (lowest priority). */
- struct badtriang *queuefront[4096];
- struct badtriang *queuetail[4096];
- int nextnonemptyq[4096];
- int firstnonemptyq;
- /* Variable that maintains the stack of recently flipped triangles. */
- struct flipstacker *lastflip;
- /* Other variables. */
- REAL xmin, xmax, ymin, ymax; /* x and y bounds. */
- REAL xminextreme; /* Nonexistent x value used as a flag in sweepline. */
- int invertices; /* Number of input vertices. */
- int inelements; /* Number of input triangles. */
- int insegments; /* Number of input segments. */
- int holes; /* Number of input holes. */
- int regions; /* Number of input regions. */
- int undeads; /* Number of input vertices that don't appear in the mesh. */
- long edges; /* Number of output edges. */
- int mesh_dim; /* Dimension (ought to be 2). */
- int nextras; /* Number of attributes per vertex. */
- int eextras; /* Number of attributes per triangle. */
- long hullsize; /* Number of edges in convex hull. */
- int steinerleft; /* Number of Steiner points not yet used. */
- int vertexmarkindex; /* Index to find boundary marker of a vertex. */
- int vertex2triindex; /* Index to find a triangle adjacent to a vertex. */
- int highorderindex; /* Index to find extra nodes for high-order elements. */
- int elemattribindex; /* Index to find attributes of a triangle. */
- int areaboundindex; /* Index to find area bound of a triangle. */
- int checksegments; /* Are there segments in the triangulation yet? */
- int checkquality; /* Has quality triangulation begun yet? */
- int readnodefile; /* Has a .node file been read? */
- long samples; /* Number of random samples for point location. */
- long incirclecount; /* Number of incircle tests performed. */
- long counterclockcount; /* Number of counterclockwise tests performed. */
- long orient3dcount; /* Number of 3D orientation tests performed. */
- long hyperbolacount; /* Number of right-of-hyperbola tests performed. */
- long circumcentercount; /* Number of circumcenter calculations performed. */
- long circletopcount; /* Number of circle top calculations performed. */
- /* Triangular bounding box vertices. */
- vertex infvertex1, infvertex2, infvertex3;
- /* Pointer to the `triangle' that occupies all of "outer space." */
- triangle *dummytri;
- triangle *dummytribase; /* Keep base address so we can free() it later. */
- /* Pointer to the omnipresent subsegment. Referenced by any triangle or */
- /* subsegment that isn't really connected to a subsegment at that */
- /* location. */
- subseg *dummysub;
- subseg *dummysubbase; /* Keep base address so we can free() it later. */
- /* Pointer to a recently visited triangle. Improves point location if */
- /* proximate vertices are inserted sequentially. */
- struct otri recenttri;
- }; /* End of `struct mesh'. */
- /* Data structure for command line switches and file names. This structure */
- /* is used (instead of global variables) to allow reentrancy. */
- struct behavior {
- /* Switches for the triangulator. */
- /* poly: -p switch. refine: -r switch. */
- /* quality: -q switch. */
- /* minangle: minimum angle bound, specified after -q switch. */
- /* goodangle: cosine squared of minangle. */
- /* offconstant: constant used to place off-center Steiner points. */
- /* vararea: -a switch without number. */
- /* fixedarea: -a switch with number. */
- /* maxarea: maximum area bound, specified after -a switch. */
- /* usertest: -u switch. */
- /* regionattrib: -A switch. convex: -c switch. */
- /* weighted: 1 for -w switch, 2 for -W switch. jettison: -j switch */
- /* firstnumber: inverse of -z switch. All items are numbered starting */
- /* from `firstnumber'. */
- /* edgesout: -e switch. voronoi: -v switch. */
- /* neighbors: -n switch. geomview: -g switch. */
- /* nobound: -B switch. nopolywritten: -P switch. */
- /* nonodewritten: -N switch. noelewritten: -E switch. */
- /* noiterationnum: -I switch. noholes: -O switch. */
- /* noexact: -X switch. */
- /* order: element order, specified after -o switch. */
- /* nobisect: count of how often -Y switch is selected. */
- /* steiner: maximum number of Steiner points, specified after -S switch. */
- /* incremental: -i switch. sweepline: -F switch. */
- /* dwyer: inverse of -l switch. */
- /* splitseg: -s switch. */
- /* conformdel: -D switch. docheck: -C switch. */
- /* quiet: -Q switch. verbose: count of how often -V switch is selected. */
- /* usesegments: -p, -r, -q, or -c switch; determines whether segments are */
- /* used at all. */
- /* */
- /* Read the instructions to find out the meaning of these switches. */
- int poly, refine, quality, vararea, fixedarea, usertest;
- int regionattrib, convex, weighted, jettison;
- int firstnumber;
- int edgesout, voronoi, neighbors, geomview;
- int nobound, nopolywritten, nonodewritten, noelewritten, noiterationnum;
- int noholes, noexact, conformdel;
- int incremental, sweepline, dwyer;
- int splitseg;
- int docheck;
- int quiet, verbose;
- int usesegments;
- int order;
- int nobisect;
- int steiner;
- REAL minangle, goodangle, offconstant;
- REAL maxarea;
- /* Variables for file names. */
- #ifndef TRILIBRARY
- char innodefilename[FILENAMESIZE];
- char inelefilename[FILENAMESIZE];
- char inpolyfilename[FILENAMESIZE];
- char areafilename[FILENAMESIZE];
- char outnodefilename[FILENAMESIZE];
- char outelefilename[FILENAMESIZE];
- char outpolyfilename[FILENAMESIZE];
- char edgefilename[FILENAMESIZE];
- char vnodefilename[FILENAMESIZE];
- char vedgefilename[FILENAMESIZE];
- char neighborfilename[FILENAMESIZE];
- char offfilename[FILENAMESIZE];
- #endif /* not TRILIBRARY */
- }; /* End of `struct behavior'. */
- /*****************************************************************************/
- /* */
- /* Mesh manipulation primitives. Each triangle contains three pointers to */
- /* other triangles, with orientations. Each pointer points not to the */
- /* first byte of a triangle, but to one of the first three bytes of a */
- /* triangle. It is necessary to extract both the triangle itself and the */
- /* orientation. To save memory, I keep both pieces of information in one */
- /* pointer. To make this possible, I assume that all triangles are aligned */
- /* to four-byte boundaries. The decode() routine below decodes a pointer, */
- /* extracting an orientation (in the range 0 to 2) and a pointer to the */
- /* beginning of a triangle. The encode() routine compresses a pointer to a */
- /* triangle and an orientation into a single pointer. My assumptions that */
- /* triangles are four-byte-aligned and that the `unsigned long' type is */
- /* long enough to hold a pointer are two of the few kludges in this program.*/
- /* */
- /* Subsegments are manipulated similarly. A pointer to a subsegment */
- /* carries both an address and an orientation in the range 0 to 1. */
- /* */
- /* The other primitives take an oriented triangle or oriented subsegment, */
- /* and return an oriented triangle or oriented subsegment or vertex; or */
- /* they change the connections in the data structure. */
- /* */
- /* Below, triangles and subsegments are denoted by their vertices. The */
- /* triangle abc has origin (org) a, destination (dest) b, and apex (apex) */
- /* c. These vertices occur in counterclockwise order about the triangle. */
- /* The handle abc may simultaneously denote vertex a, edge ab, and triangle */
- /* abc. */
- /* */
- /* Similarly, the subsegment ab has origin (sorg) a and destination (sdest) */
- /* b. If ab is thought to be directed upward (with b directly above a), */
- /* then the handle ab is thought to grasp the right side of ab, and may */
- /* simultaneously denote vertex a and edge ab. */
- /* */
- /* An asterisk (*) denotes a vertex whose identity is unknown. */
- /* */
- /* Given this notation, a partial list of mesh manipulation primitives */
- /* follows. */
- /* */
- /* */
- /* For triangles: */
- /* */
- /* sym: Find the abutting triangle; same edge. */
- /* sym(abc) -> ba* */
- /* */
- /* lnext: Find the next edge (counterclockwise) of a triangle. */
- /* lnext(abc) -> bca */
- /* */
- /* lprev: Find the previous edge (clockwise) of a triangle. */
- /* lprev(abc) -> cab */
- /* */
- /* onext: Find the next edge counterclockwise with the same origin. */
- /* onext(abc) -> ac* */
- /* */
- /* oprev: Find the next edge clockwise with the same origin. */
- /* oprev(abc) -> a*b */
- /* */
- /* dnext: Find the next edge counterclockwise with the same destination. */
- /* dnext(abc) -> *ba */
- /* */
- /* dprev: Find the next edge clockwise with the same destination. */
- /* dprev(abc) -> cb* */
- /* */
- /* rnext: Find the next edge (counterclockwise) of the adjacent triangle. */
- /* rnext(abc) -> *a* */
- /* */
- /* rprev: Find the previous edge (clockwise) of the adjacent triangle. */
- /* rprev(abc) -> b** */
- /* */
- /* org: Origin dest: Destination apex: Apex */
- /* org(abc) -> a dest(abc) -> b apex(abc) -> c */
- /* */
- /* bond: Bond two triangles together at the resepective handles. */
- /* bond(abc, bad) */
- /* */
- /* */
- /* For subsegments: */
- /* */
- /* ssym: Reverse the orientation of a subsegment. */
- /* ssym(ab) -> ba */
- /* */
- /* spivot: Find adjoining subsegment with the same origin. */
- /* spivot(ab) -> a* */
- /* */
- /* snext: Find next subsegment in sequence. */
- /* snext(ab) -> b* */
- /* */
- /* sorg: Origin sdest: Destination */
- /* sorg(ab) -> a sdest(ab) -> b */
- /* */
- /* sbond: Bond two subsegments together at the respective origins. */
- /* sbond(ab, ac) */
- /* */
- /* */
- /* For interacting tetrahedra and subfacets: */
- /* */
- /* tspivot: Find a subsegment abutting a triangle. */
- /* tspivot(abc) -> ba */
- /* */
- /* stpivot: Find a triangle abutting a subsegment. */
- /* stpivot(ab) -> ba* */
- /* */
- /* tsbond: Bond a triangle to a subsegment. */
- /* tsbond(abc, ba) */
- /* */
- /*****************************************************************************/
- /********* Mesh manipulation primitives begin here *********/
- /** **/
- /** **/
- /* Fast lookup arrays to speed some of the mesh manipulation primitives. */
- int plus1mod3[3] = {1, 2, 0};
- int minus1mod3[3] = {2, 0, 1};
- /********* Primitives for triangles *********/
- /* */
- /* */
- /* decode() converts a pointer to an oriented triangle. The orientation is */
- /* extracted from the two least significant bits of the pointer. */
- #define decode(ptr, otri)
- (otri).orient = (int) ((unsigned long) (ptr) & (unsigned long) 3l);
- (otri).tri = (triangle *)
- ((unsigned long) (ptr) ^ (unsigned long) (otri).orient)
- /* encode() compresses an oriented triangle into a single pointer. It */
- /* relies on the assumption that all triangles are aligned to four-byte */
- /* boundaries, so the two least significant bits of (otri).tri are zero. */
- #define encode(otri)
- (triangle) ((unsigned long) (otri).tri | (unsigned long) (otri).orient)
- /* The following handle manipulation primitives are all described by Guibas */
- /* and Stolfi. However, Guibas and Stolfi use an edge-based data */
- /* structure, whereas I use a triangle-based data structure. */
- /* sym() finds the abutting triangle, on the same edge. Note that the edge */
- /* direction is necessarily reversed, because the handle specified by an */
- /* oriented triangle is directed counterclockwise around the triangle. */
- #define sym(otri1, otri2)
- ptr = (otri1).tri[(otri1).orient];
- decode(ptr, otri2);
- #define symself(otri)
- ptr = (otri).tri[(otri).orient];
- decode(ptr, otri);
- /* lnext() finds the next edge (counterclockwise) of a triangle. */
- #define lnext(otri1, otri2)
- (otri2).tri = (otri1).tri;
- (otri2).orient = plus1mod3[(otri1).orient]
- #define lnextself(otri)
- (otri).orient = plus1mod3[(otri).orient]
- /* lprev() finds the previous edge (clockwise) of a triangle. */
- #define lprev(otri1, otri2)
- (otri2).tri = (otri1).tri;
- (otri2).orient = minus1mod3[(otri1).orient]
- #define lprevself(otri)
- (otri).orient = minus1mod3[(otri).orient]
- /* onext() spins counterclockwise around a vertex; that is, it finds the */
- /* next edge with the same origin in the counterclockwise direction. This */
- /* edge is part of a different triangle. */
- #define onext(otri1, otri2)
- lprev(otri1, otri2);
- symself(otri2);
- #define onextself(otri)
- lprevself(otri);
- symself(otri);
- /* oprev() spins clockwise around a vertex; that is, it finds the next edge */
- /* with the same origin in the clockwise direction. This edge is part of */
- /* a different triangle. */
- #define oprev(otri1, otri2)
- sym(otri1, otri2);
- lnextself(otri2);
- #define oprevself(otri)
- symself(otri);
- lnextself(otri);
- /* dnext() spins counterclockwise around a vertex; that is, it finds the */
- /* next edge with the same destination in the counterclockwise direction. */
- /* This edge is part of a different triangle. */
- #define dnext(otri1, otri2)
- sym(otri1, otri2);
- lprevself(otri2);
- #define dnextself(otri)
- symself(otri);
- lprevself(otri);
- /* dprev() spins clockwise around a vertex; that is, it finds the next edge */
- /* with the same destination in the clockwise direction. This edge is */
- /* part of a different triangle. */
- #define dprev(otri1, otri2)
- lnext(otri1, otri2);
- symself(otri2);
- #define dprevself(otri)
- lnextself(otri);
- symself(otri);
- /* rnext() moves one edge counterclockwise about the adjacent triangle. */
- /* (It's best understood by reading Guibas and Stolfi. It involves */
- /* changing triangles twice.) */
- #define rnext(otri1, otri2)
- sym(otri1, otri2);
- lnextself(otri2);
- symself(otri2);
- #define rnextself(otri)
- symself(otri);
- lnextself(otri);
- symself(otri);
- /* rprev() moves one edge clockwise about the adjacent triangle. */
- /* (It's best understood by reading Guibas and Stolfi. It involves */
- /* changing triangles twice.) */
- #define rprev(otri1, otri2)
- sym(otri1, otri2);
- lprevself(otri2);
- symself(otri2);
- #define rprevself(otri)
- symself(otri);
- lprevself(otri);
- symself(otri);
- /* These primitives determine or set the origin, destination, or apex of a */
- /* triangle. */
- #define org(otri, vertexptr)
- vertexptr = (vertex) (otri).tri[plus1mod3[(otri).orient] + 3]
- #define dest(otri, vertexptr)
- vertexptr = (vertex) (otri).tri[minus1mod3[(otri).orient] + 3]
- #define apex(otri, vertexptr)
- vertexptr = (vertex) (otri).tri[(otri).orient + 3]
- #define setorg(otri, vertexptr)
- (otri).tri[plus1mod3[(otri).orient] + 3] = (triangle) vertexptr
- #define setdest(otri, vertexptr)
- (otri).tri[minus1mod3[(otri).orient] + 3] = (triangle) vertexptr
- #define setapex(otri, vertexptr)
- (otri).tri[(otri).orient + 3] = (triangle) vertexptr
- /* Bond two triangles together. */
- #define bond(otri1, otri2)
- (otri1).tri[(otri1).orient] = encode(otri2);
- (otri2).tri[(otri2).orient] = encode(otri1)
- /* Dissolve a bond (from one side). Note that the other triangle will still */
- /* think it's connected to this triangle. Usually, however, the other */
- /* triangle is being deleted entirely, or bonded to another triangle, so */
- /* it doesn't matter. */
- #define dissolve(otri)
- (otri).tri[(otri).orient] = (triangle) m->dummytri
- /* Copy an oriented triangle. */
- #define otricopy(otri1, otri2)
- (otri2).tri = (otri1).tri;
- (otri2).orient = (otri1).orient
- /* Test for equality of oriented triangles. */
- #define otriequal(otri1, otri2)
- (((otri1).tri == (otri2).tri) &&
- ((otri1).orient == (otri2).orient))
- /* Primitives to infect or cure a triangle with the virus. These rely on */
- /* the assumption that all subsegments are aligned to four-byte boundaries.*/
- #define infect(otri)
- (otri).tri[6] = (triangle)
- ((unsigned long) (otri).tri[6] | (unsigned long) 2l)
- #define uninfect(otri)
- (otri).tri[6] = (triangle)
- ((unsigned long) (otri).tri[6] & ~ (unsigned long) 2l)
- /* Test a triangle for viral infection. */
- #define infected(otri)
- (((unsigned long) (otri).tri[6] & (unsigned long) 2l) != 0l)
- /* Check or set a triangle's attributes. */
- #define elemattribute(otri, attnum)
- ((REAL *) (otri).tri)[m->elemattribindex + (attnum)]
- #define setelemattribute(otri, attnum, value)
- ((REAL *) (otri).tri)[m->elemattribindex + (attnum)] = value
- /* Check or set a triangle's maximum area bound. */
- #define areabound(otri) ((REAL *) (otri).tri)[m->areaboundindex]
- #define setareabound(otri, value)
- ((REAL *) (otri).tri)[m->areaboundindex] = value
- /* Check or set a triangle's deallocation. Its second pointer is set to */
- /* NULL to indicate that it is not allocated. (Its first pointer is used */
- /* for the stack of dead items.) Its fourth pointer (its first vertex) */
- /* is set to NULL in case a `badtriang' structure points to it. */
- #define deadtri(tria) ((tria)[1] == (triangle) NULL)
- #define killtri(tria)
- (tria)[1] = (triangle) NULL;
- (tria)[3] = (triangle) NULL
- /********* Primitives for subsegments *********/
- /* */
- /* */
- /* sdecode() converts a pointer to an oriented subsegment. The orientation */
- /* is extracted from the least significant bit of the pointer. The two */
- /* least significant bits (one for orientation, one for viral infection) */
- /* are masked out to produce the real pointer. */
- #define sdecode(sptr, osub)
- (osub).ssorient = (int) ((unsigned long) (sptr) & (unsigned long) 1l);
- (osub).ss = (subseg *)
- ((unsigned long) (sptr) & ~ (unsigned long) 3l)
- /* sencode() compresses an oriented subsegment into a single pointer. It */
- /* relies on the assumption that all subsegments are aligned to two-byte */
- /* boundaries, so the least significant bit of (osub).ss is zero. */
- #define sencode(osub)
- (subseg) ((unsigned long) (osub).ss | (unsigned long) (osub).ssorient)
- /* ssym() toggles the orientation of a subsegment. */
- #define ssym(osub1, osub2)
- (osub2).ss = (osub1).ss;
- (osub2).ssorient = 1 - (osub1).ssorient
- #define ssymself(osub)
- (osub).ssorient = 1 - (osub).ssorient
- /* spivot() finds the other subsegment (from the same segment) that shares */
- /* the same origin. */
- #define spivot(osub1, osub2)
- sptr = (osub1).ss[(osub1).ssorient];
- sdecode(sptr, osub2)
- #define spivotself(osub)
- sptr = (osub).ss[(osub).ssorient];
- sdecode(sptr, osub)
- /* snext() finds the next subsegment (from the same segment) in sequence; */
- /* one whose origin is the input subsegment's destination. */
- #define snext(osub1, osub2)
- sptr = (osub1).ss[1 - (osub1).ssorient];
- sdecode(sptr, osub2)
- #define snextself(osub)
- sptr = (osub).ss[1 - (osub).ssorient];
- sdecode(sptr, osub)
- /* These primitives determine or set the origin or destination of a */
- /* subsegment or the segment that includes it. */
- #define sorg(osub, vertexptr)
- vertexptr = (vertex) (osub).ss[2 + (osub).ssorient]
- #define sdest(osub, vertexptr)
- vertexptr = (vertex) (osub).ss[3 - (osub).ssorient]
- #define setsorg(osub, vertexptr)
- (osub).ss[2 + (osub).ssorient] = (subseg) vertexptr
- #define setsdest(osub, vertexptr)
- (osub).ss[3 - (osub).ssorient] = (subseg) vertexptr
- #define segorg(osub, vertexptr)
- vertexptr = (vertex) (osub).ss[4 + (osub).ssorient]
- #define segdest(osub, vertexptr)
- vertexptr = (vertex) (osub).ss[5 - (osub).ssorient]
- #define setsegorg(osub, vertexptr)
- (osub).ss[4 + (osub).ssorient] = (subseg) vertexptr
- #define setsegdest(osub, vertexptr)
- (osub).ss[5 - (osub).ssorient] = (subseg) vertexptr
- /* These primitives read or set a boundary marker. Boundary markers are */
- /* used to hold user-defined tags for setting boundary conditions in */
- /* finite element solvers. */
- #define mark(osub) (* (int *) ((osub).ss + 8))
- #define setmark(osub, value)
- * (int *) ((osub).ss + 8) = value
- /* Bond two subsegments together. */
- #define sbond(osub1, osub2)
- (osub1).ss[(osub1).ssorient] = sencode(osub2);
- (osub2).ss[(osub2).ssorient] = sencode(osub1)
- /* Dissolve a subsegment bond (from one side). Note that the other */
- /* subsegment will still think it's connected to this subsegment. */
- #define sdissolve(osub)
- (osub).ss[(osub).ssorient] = (subseg) m->dummysub
- /* Copy a subsegment. */
- #define subsegcopy(osub1, osub2)
- (osub2).ss = (osub1).ss;
- (osub2).ssorient = (osub1).ssorient
- /* Test for equality of subsegments. */
- #define subsegequal(osub1, osub2)
- (((osub1).ss == (osub2).ss) &&
- ((osub1).ssorient == (osub2).ssorient))
- /* Check or set a subsegment's deallocation. Its second pointer is set to */
- /* NULL to indicate that it is not allocated. (Its first pointer is used */
- /* for the stack of dead items.) Its third pointer (its first vertex) */
- /* is set to NULL in case a `badsubseg' structure points to it. */
- #define deadsubseg(sub) ((sub)[1] == (subseg) NULL)
- #define killsubseg(sub)
- (sub)[1] = (subseg) NULL;
- (sub)[2] = (subseg) NULL
- /********* Primitives for interacting triangles and subsegments *********/
- /* */
- /* */
- /* tspivot() finds a subsegment abutting a triangle. */
- #define tspivot(otri, osub)
- sptr = (subseg) (otri).tri[6 + (otri).orient];
- sdecode(sptr, osub)
- /* stpivot() finds a triangle abutting a subsegment. It requires that the */
- /* variable `ptr' of type `triangle' be defined. */
- #define stpivot(osub, otri)
- ptr = (triangle) (osub).ss[6 + (osub).ssorient];
- decode(ptr, otri)
- /* Bond a triangle to a subsegment. */
- #define tsbond(otri, osub)
- (otri).tri[6 + (otri).orient] = (triangle) sencode(osub);
- (osub).ss[6 + (osub).ssorient] = (subseg) encode(otri)
- /* Dissolve a bond (from the triangle side). */
- #define tsdissolve(otri)
- (otri).tri[6 + (otri).orient] = (triangle) m->dummysub
- /* Dissolve a bond (from the subsegment side). */
- #define stdissolve(osub)
- (osub).ss[6 + (osub).ssorient] = (subseg) m->dummytri
- /********* Primitives for vertices *********/
- /* */
- /* */
- #define vertexmark(vx) ((int *) (vx))[m->vertexmarkindex]
- #define setvertexmark(vx, value)
- ((int *) (vx))[m->vertexmarkindex] = value
- #define vertextype(vx) ((int *) (vx))[m->vertexmarkindex + 1]
- #define setvertextype(vx, value)
- ((int *) (vx))[m->vertexmarkindex + 1] = value
- #define vertex2tri(vx) ((triangle *) (vx))[m->vertex2triindex]
- #define setvertex2tri(vx, value)
- ((triangle *) (vx))[m->vertex2triindex] = value
- /** **/
- /** **/
- /********* Mesh manipulation primitives end here *********/
- /********* User-defined triangle evaluation routine begins here *********/
- /** **/
- /** **/
- /*****************************************************************************/
- /* */
- /* triunsuitable() Determine if a triangle is unsuitable, and thus must */
- /* be further refined. */
- /* */
- /* You may write your own procedure that decides whether or not a selected */
- /* triangle is too big (and needs to be refined). There are two ways to do */
- /* this. */
- /* */
- /* (1) Modify the procedure `triunsuitable' below, then recompile */
- /* Triangle. */
- /* */
- /* (2) Define the symbol EXTERNAL_TEST (either by adding the definition */
- /* to this file, or by using the appropriate compiler switch). This way, */
- /* you can compile triangle.c separately from your test. Write your own */
- /* `triunsuitable' procedure in a separate C file (using the same prototype */
- /* as below). Compile it and link the object code with triangle.o. */
- /* */
- /* This procedure returns 1 if the triangle is too large and should be */
- /* refined; 0 otherwise. */
- /* */
- /*****************************************************************************/
- #ifdef EXTERNAL_TEST
- int triunsuitable();
- #else /* not EXTERNAL_TEST */
- #ifdef ANSI_DECLARATORS
- int triunsuitable(vertex triorg, vertex tridest, vertex triapex, REAL area)
- #else /* not ANSI_DECLARATORS */
- int triunsuitable(triorg, tridest, triapex, area)
- vertex triorg; /* The triangle's origin vertex. */
- vertex tridest; /* The triangle's destination vertex. */
- vertex triapex; /* The triangle's apex vertex. */
- REAL area; /* The area of the triangle. */
- #endif /* not ANSI_DECLARATORS */
- {
- REAL dxoa, dxda, dxod;
- REAL dyoa, dyda, dyod;
- REAL oalen, dalen, odlen;
- REAL maxlen;
- dxoa = triorg[0] - triapex[0];
- dyoa = triorg[1] - triapex[1];
- dxda = tridest[0] - triapex[0];
- dyda = tridest[1] - triapex[1];
- dxod = triorg[0] - tridest[0];
- dyod = triorg[1] - tridest[1];
- /* Find the squares of the lengths of the triangle's three edges. */
- oalen = dxoa * dxoa + dyoa * dyoa;
- dalen = dxda * dxda + dyda * dyda;
- odlen = dxod * dxod + dyod * dyod;
- /* Find the square of the length of the longest edge. */
- maxlen = (dalen > oalen) ? dalen : oalen;
- maxlen = (odlen > maxlen) ? odlen : maxlen;
- if (maxlen > 0.05 * (triorg[0] * triorg[0] + triorg[1] * triorg[1]) + 0.02) {
- return 1;
- } else {
- return 0;
- }
- }
- #endif /* not EXTERNAL_TEST */
- /** **/
- /** **/
- /********* User-defined triangle evaluation routine ends here *********/
- /********* Memory allocation and program exit wrappers begin here *********/
- /** **/
- /** **/
- #ifdef ANSI_DECLARATORS
- void triexit(int status)
- #else /* not ANSI_DECLARATORS */
- void triexit(status)
- int status;
- #endif /* not ANSI_DECLARATORS */
- {
- exit(status);
- }
- #ifdef ANSI_DECLARATORS
- VOID *trimalloc(int size)
- #else /* not ANSI_DECLARATORS */
- VOID *trimalloc(size)
- int size;
- #endif /* not ANSI_DECLARATORS */
- {
- VOID *memptr;
- memptr = (VOID *) malloc((unsigned int) size);
- if (memptr == (VOID *) NULL) {
- printf("Error: Out of memory.n");
- triexit(1);
- }
- return(memptr);
- }
- #ifdef ANSI_DECLARATORS
- void trifree(VOID *memptr)
- #else /* not ANSI_DECLARATORS */
- void trifree(memptr)
- VOID *memptr;
- #endif /* not ANSI_DECLARATORS */
- {
- free(memptr);
- }
- /** **/
- /** **/
- /********* Memory allocation and program exit wrappers end here *********/
- /********* User interaction routines begin here *********/
- /** **/
- /** **/
- /*****************************************************************************/
- /* */
- /* syntax() Print list of command line switches. */
- /* */
- /*****************************************************************************/
- #ifndef TRILIBRARY
- void syntax()
- {
- #ifdef CDT_ONLY
- #ifdef REDUCED
- printf("triangle [-pAcjevngBPNEIOXzo_lQVh] input_filen");
- #else /* not REDUCED */
- printf("triangle [-pAcjevngBPNEIOXzo_iFlCQVh] input_filen");
- #endif /* not REDUCED */
- #else /* not CDT_ONLY */
- #ifdef REDUCED
- printf("triangle [-prq__a__uAcDjevngBPNEIOXzo_YS__lQVh] input_filen");
- #else /* not REDUCED */
- printf("triangle [-prq__a__uAcDjevngBPNEIOXzo_YS__iFlsCQVh] input_filen");
- #endif /* not REDUCED */
- #endif /* not CDT_ONLY */
- printf(" -p Triangulates a Planar Straight Line Graph (.poly file).n");
- #ifndef CDT_ONLY
- printf(" -r Refines a previously generated mesh.n");
- printf(
- " -q Quality mesh generation. A minimum angle may be specified.n");
- printf(" -a Applies a maximum triangle area constraint.n");
- printf(" -u Applies a user-defined triangle constraint.n");
- #endif /* not CDT_ONLY */
- printf(
- " -A Applies attributes to identify triangles in certain regions.n");
- printf(" -c Encloses the convex hull with segments.n");
- #ifndef CDT_ONLY
- printf(" -D Conforming Delaunay: all triangles are truly Delaunay.n");
- #endif /* not CDT_ONLY */
- /*
- printf(" -w Weighted Delaunay triangulation.n");
- printf(" -W Regular triangulation (lower hull of a height field).n");
- */
- printf(" -j Jettison unused vertices from output .node file.n");
- printf(" -e Generates an edge list.n");
- printf(" -v Generates a Voronoi diagram.n");
- printf(" -n Generates a list of triangle neighbors.n");
- printf(" -g Generates an .off file for Geomview.n");
- printf(" -B Suppresses output of boundary information.n");
- printf(" -P Suppresses output of .poly file.n");
- printf(" -N Suppresses output of .node file.n");
- printf(" -E Suppresses output of .ele file.n");
- printf(" -I Suppresses mesh iteration numbers.n");
- printf(" -O Ignores holes in .poly file.n");
- printf(" -X Suppresses use of exact arithmetic.n");
- printf(" -z Numbers all items starting from zero (rather than one).n");
- printf(" -o2 Generates second-order subparametric elements.n");
- #ifndef CDT_ONLY
- printf(" -Y Suppresses boundary segment splitting.n");
- printf(" -S Specifies maximum number of added Steiner points.n");
- #endif /* not CDT_ONLY */
- #ifndef REDUCED
- printf(" -i Uses incremental method, rather than divide-and-conquer.n");
- printf(" -F Uses Fortune's sweepline algorithm, rather than d-and-c.n");
- #endif /* not REDUCED */
- printf(" -l Uses vertical cuts only, rather than alternating cuts.n");
- #ifndef REDUCED
- #ifndef CDT_ONLY
- printf(
- " -s Force segments into mesh by splitting (instead of using CDT).n");
- #endif /* not CDT_ONLY */
- printf(" -C Check consistency of final mesh.n");
- #endif /* not REDUCED */
- printf(" -Q Quiet: No terminal output except errors.n");
- printf(" -V Verbose: Detailed information on what I'm doing.n");
- printf(" -h Help: Detailed instructions for Triangle.n");
- triexit(0);
- }
- #endif /* not TRILIBRARY */
- /*****************************************************************************/
- /* */
- /* info() Print out complete instructions. */
- /* */
- /*****************************************************************************/
- #ifndef TRILIBRARY
- void info()
- {
- printf("Trianglen");
- printf(
- "A Two-Dimensional Quality Mesh Generator and Delaunay Triangulator.n");
- printf("Version 1.6nn");
- printf(
- "Copyright 1993, 1995, 1997, 1998, 2002, 2005 Jonathan Richard Shewchukn");
- printf("2360 Woolsey #H / Berkeley, California 94705-1927n");
- printf("Bugs/comments to jrs@cs.berkeley.edun");
- printf(
- "Created as part of the Quake project (tools for earthquake simulation).n");
- printf(
- "Supported in part by NSF Grant CMS-9318163 and an NSERC 1967 Scholarship.n");
- printf("There is no warranty whatsoever. Use at your own risk.n");
- #ifdef SINGLE
- printf("This executable is compiled for single precision arithmetic.nnn");
- #else /* not SINGLE */
- printf("This executable is compiled for double precision arithmetic.nnn");
- #endif /* not SINGLE */
- printf(
- "Triangle generates exact Delaunay triangulations, constrained Delaunayn");
- printf(
- "triangulations, conforming Delaunay triangulations, Voronoi diagrams, andn");
- printf(
- "high-quality triangular meshes. The latter can be generated with no smalln"
- );
- printf(
- "or large angles, and are thus suitable for finite element analysis. If non"
- );
- printf(
- "command line switch is specified, your .node input file is read, and then");
- printf(
- "Delaunay triangulation is returned in .node and .ele output files. Then");
- printf("command syntax is:nn");
- printf("triangle [-prq__a__uAcDjevngBPNEIOXzo_YS__iFlsCQVh] input_filenn");
- printf(
- "Underscores indicate that numbers may optionally follow certain switches.n");
- printf(
- "Do not leave any space between a switch and its numeric parameter.n");
- printf(
- "input_file must be a file with extension .node, or extension .poly if then");
- printf(
- "-p switch is used. If -r is used, you must supply .node and .ele files,n");
- printf(
- "and possibly a .poly file and an .area file as well. The formats of thesen"
- );
- printf("files are described below.nn");
- printf("Command Line Switches:nn");
- printf(
- " -p Reads a Planar Straight Line Graph (.poly file), which can specifyn"
- );
- printf(
- " vertices, segments, holes, regional attributes, and regional arean");
- printf(
- " constraints. Generates a constrained Delaunay triangulation (CDT)n"
- );
- printf(
- " fitting the input; or, if -s, -q, -a, or -u is used, a conformingn");
- printf(
- " constrained Delaunay triangulation (CCDT). If you want a trulyn");
- printf(
- " Delaunay (not just constrained Delaunay) triangulation, use -D asn");
- printf(
- " well. When -p is not used, Triangle reads a .node file by default.n"
- );
- printf(
- " -r Refines a previously generated mesh. The mesh is read from a .noden"
- );
- printf(
- " file and an .ele file. If -p is also used, a .poly file is readn");
- printf(
- " and used to constrain segments in the mesh. If -a is also usedn");
- printf(
- " (with no number following), an .area file is read and used ton");
- printf(
- " impose area constraints on the mesh. Further details on refinementn"
- );
- printf(" appear below.n");
- printf(
- " -q Quality mesh generation by Delaunay refinement (a hybrid of Pauln");
- printf(
- " Chew's and Jim Ruppert's algorithms). Adds vertices to the mesh ton"
- );
- printf(
- " ensure that all angles are between 20 and 140 degrees. Ann");
- printf(
- " alternative bound on the minimum angle, replacing 20 degrees, mayn");
- printf(
- " be specified after the `q'. The specified angle may include an");
- printf(
- " decimal point, but not exponential notation. Note that a bound ofn"
- );
- printf(
- " theta degrees on the smallest angle also implies a bound ofn");
- printf(
- " (180 - 2 theta) on the largest angle. If the minimum angle is 28.6n"
- );
- printf(
- " degrees or smaller, Triangle is mathematically guaranteed ton");
- printf(
- " terminate (assuming infinite precision arithmetic--Triangle mayn");
- printf(
- " fail to terminate if you run out of precision). In practice,n");
- printf(
- " Triangle often succeeds for minimum angles up to 34 degrees. Forn");
- printf(
- " some meshes, however, you might need to reduce the minimum angle ton"
- );
- printf(
- " avoid problems associated with insufficient floating-pointn");
- printf(" precision.n");
- printf(
- " -a Imposes a maximum triangle area. If a number follows the `a', non");
- printf(
- " triangle is generated whose area is larger than that number. If non"
- );
- printf(
- " number is specified, an .area file (if -r is used) or .poly filen");
- printf(
- " (if -r is not used) specifies a set of maximum area constraints.n");
- printf(
- " An .area file contains a separate area constraint for eachn");
- printf(
- " triangle, and is useful for refining a finite element mesh based onn"
- );
- printf(
- " a posteriori error estimates. A .poly file can optionally containn"
- );
- printf(
- " an area constraint for each segment-bounded region, therebyn");
- printf(
- " controlling triangle densities in a first triangulation of a PSLG.n"
- );
- printf(
- " You can impose both a fixed area constraint and a varying arean");
- printf(
- " constraint by invoking the -a switch twice, once with and oncen");
- printf(
- " without a number following. Each area specified may include an");
- printf(" decimal point.n");
- printf(
- " -u Imposes a user-defined constraint on triangle size. There are twon"
- );
- printf(
- " ways to use this feature. One is to edit the triunsuitable()n");
- printf(
- " procedure in triangle.c to encode any constraint you like, thenn");
- printf(
- " recompile Triangle. The other is to compile triangle.c with then");
- printf(
- " EXTERNAL_TEST symbol set (compiler switch -DEXTERNAL_TEST), thenn");
- printf(
- " link Triangle with a separate object file that implementsn");
- printf(
- " triunsuitable(). In either case, the -u switch causes the user-n");
- printf(" defined test to be applied to every triangle.n");
- printf(
- " -A Assigns an additional floating-point attribute to each trianglen");
- printf(
- " that identifies what segment-bounded region each triangle belongsn");
- printf(
- " to. Attributes are assigned to regions by the .poly file. If an");
- printf(
- " region is not explicitly marked by the .poly file, triangles inn");
- printf(
- " that region are assigned an attribute of zero. The -A switch hasn");
- printf(
- " an effect only when the -p switch is used and the -r switch is not.n"
- );
- printf(
- " -c Creates segments on the convex hull of the triangulation. If youn");
- printf(
- " are triangulating a vertex set, this switch causes a .poly file ton"
- );
- printf(
- " be written, containing all edges of the convex hull. If you aren");
- printf(
- " triangulating a PSLG, this switch specifies that the whole convexn");
- printf(
- " hull of the PSLG should be triangulated, regardless of whatn");
- printf(
- " segments the PSLG has. If you do not use this switch whenn");
- printf(
- " triangulating a PSLG, Triangle assumes that you have identified then"
- );
- printf(
- " region to be triangulated by surrounding it with segments of then");
- printf(
- " input PSLG. Beware: if you are not careful, this switch can causen"
- );
- printf(
- " the introduction of an extremely thin angle between a PSLG segmentn"
- );
- printf(
- " and a convex hull segment, which can cause overrefinement (andn");
- printf(
- " possibly failure if Triangle runs out of precision). If you aren");
- printf(
- " refining a mesh, the -c switch works differently: it causes an");
- printf(
- " .poly file to be written containing the boundary edges of the meshn"
- );
- printf(" (useful if no .poly file was read).n");
- printf(
- " -D Conforming Delaunay triangulation: use this switch if you want ton"
- );
- printf(
- " ensure that all the triangles in the mesh are Delaunay, and notn");
- printf(
- " merely constrained Delaunay; or if you want to ensure that all then"
- );
- printf(
- " Voronoi vertices lie within the triangulation. (Some finite volumen"
- );
- printf(
- " methods have this requirement.) This switch invokes Ruppert'sn");
- printf(
- " original algorithm, which splits every subsegment whose diametraln");
- printf(
- " circle is encroached. It usually increases the number of verticesn"
- );
- printf(" and triangles.n");
- printf(
- " -j Jettisons vertices that are not part of the final triangulationn");
- printf(
- " from the output .node file. By default, Triangle copies alln");
- printf(
- " vertices in the input .node file to the output .node file, in then");
- printf(
- " same order, so their indices do not change. The -j switch preventsn"
- );
- printf(
- " duplicated input vertices, or vertices `eaten' by holes, fromn");
- printf(
- " appearing in the output .node file. Thus, if two input verticesn");
- printf(
- " have exactly the same coordinates, only the first appears in then");
- printf(
- " output. If any vertices are jettisoned, the vertex numbering inn");
- printf(
- " the output .node file differs from that of the input .node file.n");
- printf(
- " -e Outputs (to an .edge file) a list of edges of the triangulation.n");
- printf(
- " -v Outputs the Voronoi diagram associated with the triangulation.n");
- printf(
- " Does not attempt to detect degeneracies, so some Voronoi verticesn");
- printf(
- " may be duplicated. See the discussion of Voronoi diagrams below.n");
- printf(
- " -n Outputs (to a .neigh file) a list of triangles neighboring eachn");
- printf(" triangle.n");
- printf(
- " -g Outputs the mesh to an Object File Format (.off) file, suitable forn"
- );
- printf(" viewing with the Geometry Center's Geomview package.n");
- printf(
- " -B No boundary markers in the output .node, .poly, and .edge outputn");
- printf(
- " files. See the detailed discussion of boundary markers below.n");
- printf(
- " -P No output .poly file. Saves disk space, but you lose the abilityn");
- printf(
- " to maintain constraining segments on later refinements of the mesh.n"
- );
- printf(" -N No output .node file.n");
- printf(" -E No output .ele file.n");
- printf(
- " -I No iteration numbers. Suppresses the output of .node and .polyn");
- printf(
- " files, so your input files won't be overwritten. (If your input isn"
- );
- printf(
- " a .poly file only, a .node file is written.) Cannot be used withn");
- printf(
- " the -r switch, because that would overwrite your input .ele file.n");
- printf(
- " Shouldn't be used with the -q, -a, -u, or -s switch if you aren");
- printf(
- " using a .node file for input, because no .node file is written, son"
- );
- printf(" there is no record of any added Steiner points.n");
- printf(" -O No holes. Ignores the holes in the .poly file.n");
- printf(
- " -X No exact arithmetic. Normally, Triangle uses exact floating-pointn"
- );
- printf(
- " arithmetic for certain tests if it thinks the inexact tests are notn"
- );
- printf(
- " accurate enough. Exact arithmetic ensures the robustness of then");
- printf(
- " triangulation algorithms, despite floating-point roundoff error.n");
- printf(
- " Disabling exact arithmetic with the -X switch causes a smalln");
- printf(
- " improvement in speed and creates the possibility that Triangle willn"
- );
- printf(" fail to produce a valid mesh. Not recommended.n");
- printf(
- " -z Numbers all items starting from zero (rather than one). Note thatn"
- );
- printf(
- " this switch is normally overridden by the value used to number then"
- );
- printf(
- " first vertex of the input .node or .poly file. However, thisn");
- printf(
- " switch is useful when calling Triangle from another program.n");
- printf(
- " -o2 Generates second-order subparametric elements with six nodes each.n"
- );
- printf(
- " -Y No new vertices on the boundary. This switch is useful when then");
- printf(
- " mesh boundary must be preserved so that it conforms to somen");
- printf(
- " adjacent mesh. Be forewarned that you will probably sacrifice muchn"
- );
- printf(
- " of the quality of the mesh; Triangle will try, but the resultingn");
- printf(
- " mesh may contain poorly shaped triangles. Works well if all then");
- printf(
- " boundary vertices are closely spaced. Specify this switch twicen");
- printf(
- " (`-YY') to prevent all segment splitting, including internaln");
- printf(" boundaries.n");
- printf(
- " -S Specifies the maximum number of Steiner points (vertices that aren");
- printf(
- " not in the input, but are added to meet the constraints on minimumn"
- );
- printf(
- " angle and maximum area). The default is to allow an unlimitedn");
- printf(
- " number. If you specify this switch with no number after it,n");
- printf(
- " the limit is set to zero. Triangle always adds vertices at segmentn"
- );
- printf(
- " intersections, even if it needs to use more vertices than the limitn"
- );
- printf(
- " you set. When Triangle inserts segments by splitting (-s), itn");
- printf(
- " always adds enough vertices to ensure that all the segments of then"
- );
- printf(" PLSG are recovered, ignoring the limit if necessary.n");
- printf(
- " -i Uses an incremental rather than a divide-and-conquer algorithm ton");
- printf(
- " construct a Delaunay triangulation. Try it if the divide-and-n");
- printf(" conquer algorithm fails.n");
- printf(
- " -F Uses Steven Fortune's sweepline algorithm to construct a Delaunayn");
- printf(
- " triangulation. Warning: does not use exact arithmetic for alln");
- printf(" calculations. An exact result is not guaranteed.n");
- printf(
- " -l Uses only vertical cuts in the divide-and-conquer algorithm. Byn");
- printf(
- " default, Triangle alternates between vertical and horizontal cuts,n"
- );
- printf(
- " which usually improve the speed except with vertex sets that aren");
- printf(
- " small or short and wide. This switch is primarily of theoreticaln");
- printf(" interest.n");
- printf(
- " -s Specifies that segments should be forced into the triangulation byn"
- );
- printf(
- " recursively splitting them at their midpoints, rather than byn");
- printf(
- " generating a constrained Delaunay triangulation. Segment splittingn"
- );
- printf(
- " is true to Ruppert's original algorithm, but can create needlesslyn"
- );
- printf(
- " small triangles. This switch is primarily of theoretical interest.n"
- );
- printf(
- " -C Check the consistency of the final mesh. Uses exact arithmetic forn"
- );
- printf(
- " checking, even if the -X switch is used. Useful if you suspectn");
- printf(" Triangle is buggy.n");
- printf(
- " -Q Quiet: Suppresses all explanation of what Triangle is doing,n");
- printf(" unless an error occurs.n");
- printf(
- " -V Verbose: Gives detailed information about what Triangle is doing.n"
- );
- printf(
- " Add more `V's for increasing amount of detail. `-V' is mostn");
- printf(
- " useful; itgives information on algorithmic progress and much moren");
- printf(
- " detailed statistics. `-VV' gives vertex-by-vertex details, andn");
- printf(
- " prints so much that Triangle runs much more slowly. `-VVVV' givesn"
- );
- printf(" information only a debugger could love.n");
- printf(" -h Help: Displays these instructions.n");
- printf("n");
- printf("Definitions:n");
- printf("n");
- printf(
- " A Delaunay triangulation of a vertex set is a triangulation whosen");
- printf(
- " vertices are the vertex set, that covers the convex hull of the vertexn");
- printf(
- " set. A Delaunay triangulation has the property that no vertex liesn");
- printf(
- " inside the circumscribing circle (circle that passes through all threen");
- printf(" vertices) of any triangle in the triangulation.nn");
- printf(
- " A Voronoi diagram of a vertex set is a subdivision of the plane inton");
- printf(
- " polygonal cells (some of which may be unbounded, meaning infinitelyn");
- printf(
- " large), where each cell is the set of points in the plane that are closern"
- );
- printf(
- " to some input vertex than to any other input vertex. The Voronoi diagramn"
- );
- printf(" is a geometric dual of the Delaunay triangulation.nn");
- printf(
- " A Planar Straight Line Graph (PSLG) is a set of vertices and segments.n");
- printf(
- " Segments are simply edges, whose endpoints are all vertices in the PSLG.n"
- );
- printf(
- " Segments may intersect each other only at their endpoints. The filen");
- printf(" format for PSLGs (.poly files) is described below.nn");
- printf(
- " A constrained Delaunay triangulation (CDT) of a PSLG is similar to an");
- printf(
- " Delaunay triangulation, but each PSLG segment is present as a single edgen"
- );
- printf(
- " of the CDT. (A constrained Delaunay triangulation is not truly an");
- printf(
- " Delaunay triangulation, because some of its triangles might not ben");
- printf(
- " Delaunay.) By definition, a CDT does not have any vertices other thann");
- printf(
- " those specified in the input PSLG. Depending on context, a CDT mightn");
- printf(
- " cover the convex hull of the PSLG, or it might cover only a segment-n");
- printf(" bounded region (e.g. a polygon).nn");
- printf(
- " A conforming Delaunay triangulation of a PSLG is a triangulation in whichn"
- );
- printf(
- " each triangle is truly Delaunay, and each PSLG segment is represented byn"
- );
- printf(
- " a linear contiguous sequence of edges of the triangulation. New verticesn"
- );
- printf(
- " (not part of the PSLG) may appear, and each input segment may have beenn");
- printf(
- " subdivided into shorter edges (subsegments) by these additional vertices.n"
- );
- printf(
- " The new vertices are frequently necessary to maintain the Delaunayn");
- printf(" property while ensuring that every segment is represented.nn");
- printf(
- " A conforming constrained Delaunay triangulation (CCDT) of a PSLG is an");
- printf(
- " triangulation of a PSLG whose triangles are constrained Delaunay. Newn");
- printf(" vertices may appear, and input segments may be subdivided inton");
- printf(
- " subsegments, but not to guarantee that segments are respected; rather, ton"
- );
- printf(
- " improve the quality of the triangles. The high-quality meshes producedn");
- printf(
- " by the -q switch are usually CCDTs, but can be made conforming Delaunayn");
- printf(" with the -D switch.nn");
- printf("File Formats:nn");
- printf(
- " All files may contain comments prefixed by the character '#'. Vertices,n"
- );
- printf(
- " triangles, edges, holes, and maximum area constraints must be numberedn");
- printf(
- " consecutively, starting from either 1 or 0. Whichever you choose, alln");
- printf(
- " input files must be consistent; if the vertices are numbered from 1, son");
- printf(
- " must be all other objects. Triangle automatically detects your choicen");
- printf(
- " while reading the .node (or .poly) file. (When calling Triangle fromn");
- printf(
- " another program, use the -z switch if you wish to number objects fromn");
- printf(" zero.) Examples of these file formats are given below.nn");
- printf(" .node files:n");
- printf(
- " First line: <# of vertices> <dimension (must be 2)> <# of attributes>n"
- );
- printf(
- " <# of boundary markers (0 or 1)>n"
- );
- printf(
- " Remaining lines: <vertex #> <x> <y> [attributes] [boundary marker]n");
- printf("n");
- printf(
- " The attributes, which are typically floating-point values of physicaln");
- printf(
- " quantities (such as mass or conductivity) associated with the nodes ofn"
- );
- printf(
- " a finite element mesh, are copied unchanged to the output mesh. If -q,n"
- );
- printf(
- " -a, -u, -D, or -s is selected, each new Steiner point added to the meshn"
- );
- printf(" has attributes assigned to it by linear interpolation.nn");
- printf(
- " If the fourth entry of the first line is `1', the last column of then");
- printf(
- " remainder of the file is assumed to contain boundary markers. Boundaryn"
- );
- printf(
- " markers are used to identify boundary vertices and vertices resting onn"
- );
- printf(
- " PSLG segments; a complete description appears in a section below. Then"
- );
- printf(
- " .node file produced by Triangle contains boundary markers in the lastn");
- printf(" column unless they are suppressed by the -B switch.nn");
- printf(" .ele files:n");
- printf(
- " First line: <# of triangles> <nodes per triangle> <# of attributes>n");
- printf(
- " Remaining lines: <triangle #> <node> <node> <node> ... [attributes]n");
- printf("n");
- printf(
- " Nodes are indices into the corresponding .node file. The first threen");
- printf(
- " nodes are the corner vertices, and are listed in counterclockwise ordern"
- );
- printf(
- " around each triangle. (The remaining nodes, if any, depend on the typen"
- );
- printf(" of finite element used.)nn");
- printf(
- " The attributes are just like those of .node files. Because there is non"
- );
- printf(
- " simple mapping from input to output triangles, Triangle attempts ton");
- printf(
- " interpolate attributes, and may cause a lot of diffusion of attributesn"
- );
- printf(
- " among nearby triangles as the triangulation is refined. Attributes don"
- );
- printf(" not diffuse across segments, so attributes used to identifyn");
- printf(" segment-bounded regions remain intact.nn");
- printf(
- " In .ele files produced by Triangle, each triangular element has threen");
- printf(
- " nodes (vertices) unless the -o2 switch is used, in which casen");
- printf(
- " subparametric quadratic elements with six nodes each are generated.n");
- printf(
- " The first three nodes are the corners in counterclockwise order, andn");
- printf(
- " the fourth, fifth, and sixth nodes lie on the midpoints of the edgesn");
- printf(
- " opposite the first, second, and third vertices, respectively.n");
- printf("n");
- printf(" .poly files:n");
- printf(
- " First line: <# of vertices> <dimension (must be 2)> <# of attributes>n"
- );
- printf(
- " <# of boundary markers (0 or 1)>n"
- );
- printf(
- " Following lines: <vertex #> <x> <y> [attributes] [boundary marker]n");
- printf(" One line: <# of segments> <# of boundary markers (0 or 1)>n");
- printf(
- " Following lines: <segment #> <endpoint> <endpoint> [boundary marker]n");
- printf(" One line: <# of holes>n");
- printf(" Following lines: <hole #> <x> <y>n");
- printf(
- " Optional line: <# of regional attributes and/or area constraints>n");
- printf(
- " Optional following lines: <region #> <x> <y> <attribute> <max area>n");
- printf("n");
- printf(
- " A .poly file represents a PSLG, as well as some additional information.n"
- );
- printf(
- " The first section lists all the vertices, and is identical to then");
- printf(
- " format of .node files. <# of vertices> may be set to zero to indicaten"
- );
- printf(
- " that the vertices are listed in a separate .node file; .poly filesn");
- printf(
- " produced by Triangle always have this format. A vertex set representedn"
- );
- printf(
- " this way has the advantage that it may easily be triangulated with orn");
- printf(
- " without segments (depending on whether the -p switch is invoked).n");
- printf("n");
- printf(
- " The second section lists the segments. Segments are edges whosen");
- printf(
- " presence in the triangulation is enforced. (Depending on the choice ofn"
- );
- printf(
- " switches, segment might be subdivided into smaller edges). Eachn");
- printf(
- " segment is specified by listing the indices of its two endpoints. Thisn"
- );
- printf(
- " means that you must include its endpoints in the vertex list. Eachn");
- printf(" segment, like each point, may have a boundary marker.nn");
- printf(
- " If -q, -a, -u, and -s are not selected, Triangle produces a constrainedn"
- );
- printf(
- " Delaunay triangulation (CDT), in which each segment appears as a singlen"
- );
- printf(
- " edge in the triangulation. If -q, -a, -u, or -s is selected, Trianglen"
- );
- printf(
- " produces a conforming constrained Delaunay triangulation (CCDT), inn");
- printf(
- " which segments may be subdivided into smaller edges. If -D isn");
- printf(
- " selected, Triangle produces a conforming Delaunay triangulation, son");
- printf(
- " that every triangle is Delaunay, and not just constrained Delaunay.n");
- printf("n");
- printf(
- " The third section lists holes (and concavities, if -c is selected) inn");
- printf(
- " the triangulation. Holes are specified by identifying a point insiden");
- printf(
- " each hole. After the triangulation is formed, Triangle creates holesn");
- printf(
- " by eating triangles, spreading out from each hole point until itsn");
- printf(
- " progress is blocked by segments in the PSLG. You must be careful ton");
- printf(
- " enclose each hole in segments, or your whole triangulation might ben");
- printf(
- " eaten away. If the two triangles abutting a segment are eaten, then");
- printf(
- " segment itself is also eaten. Do not place a hole directly on an");
- printf(" segment; if you do, Triangle chooses one side of the segmentn");
- printf(" arbitrarily.nn");
- printf(
- " The optional fourth section lists regional attributes (to be assignedn");
- printf(
- " to all triangles in a region) and regional constraints on the maximumn");
- printf(
- " triangle area. Triangle reads this section only if the -A switch isn");
- printf(
- " used or the -a switch is used without a number following it, and the -rn"
- );
- printf(
- " switch is not used. Regional attributes and area constraints aren");
- printf(
- " propagated in the same manner as holes: you specify a point for eachn");
- printf(
- " attribute and/or constraint, and the attribute and/or constraintn");
- printf(
- " affects the whole region (bounded by segments) containing the point.n");
- printf(
- " If two values are written on a line after the x and y coordinate, then");
- printf(
- " first such value is assumed to be a regional attribute (but is onlyn");
- printf(
- " applied if the -A switch is selected), and the second value is assumedn"
- );
- printf(
- " to be a regional area constraint (but is only applied if the -a switchn"
- );
- printf(
- " is selected). You may specify just one value after the coordinates,n");
- printf(
- " which can serve as both an attribute and an area constraint, dependingn"
- );
- printf(
- " on the choice of switches. If you are using the -A and -a switchesn");
- printf(
- " simultaneously and wish to assign an attribute to some region withoutn");
- printf(" imposing an area constraint, use a negative maximum area.nn");
- printf(
- " When a triangulation is created from a .poly file, you must eithern");
- printf(
- " enclose the entire region to be triangulated in PSLG segments, orn");
- printf(
- " use the -c switch, which automatically creates extra segments thatn");
- printf(
- " enclose the convex hull of the PSLG. If you do not use the -c switch,n"
- );
- printf(
- " Triangle eats all triangles that are not enclosed by segments; if youn");
- printf(
- " are not careful, your whole triangulation may be eaten away. If you don"
- );
- printf(
- " use the -c switch, you can still produce concavities by the appropriaten"
- );
- printf(
- " placement of holes just inside the boundary of the convex hull.n");
- printf("n");
- printf(
- " An ideal PSLG has no intersecting segments, nor any vertices that lien");
- printf(
- " upon segments (except, of course, the endpoints of each segment). Youn"
- );
- printf(
- " aren't required to make your .poly files ideal, but you should be awaren"
- );
- printf(
- " of what can go wrong. Segment intersections are relatively safe--n");
- printf(
- " Triangle calculates the intersection points for you and adds them ton");
- printf(
- " the triangulation--as long as your machine's floating-point precisionn");
- printf(
- " doesn't become a problem. You are tempting the fates if you have threen"
- );
- printf(
- " segments that cross at the same location, and expect Triangle to figuren"
- );
- printf(
- " out where the intersection point is. Thanks to floating-point roundoffn"
- );
- printf(
- " error, Triangle will probably decide that the three segments intersectn"
- );
- printf(
- " at three different points, and you will find a minuscule triangle inn");
- printf(
- " your output--unless Triangle tries to refine the tiny triangle, usesn");
- printf(
- " up the last bit of machine precision, and fails to terminate at all.n");
- printf(
- " You're better off putting the intersection point in the input files,n");
- printf(
- " and manually breaking up each segment into two. Similarly, if youn");
- printf(
- " place a vertex at the middle of a segment, and hope that Triangle willn"
- );
- printf(
- " break up the segment at that vertex, you might get lucky. On the othern"
- );
- printf(
- " hand, Triangle might decide that the vertex doesn't lie precisely onn");
- printf(
- " the segment, and you'll have a needle-sharp triangle in your output--orn"
- );
- printf(" a lot of tiny triangles if you're generating a quality mesh.n");
- printf("n");
- printf(
- " When Triangle reads a .poly file, it also writes a .poly file, whichn");
- printf(
- " includes all the subsegments--the edges that are parts of inputn");
- printf(
- " segments. If the -c switch is used, the output .poly file alson");
- printf(
- " includes all of the edges on the convex hull. Hence, the output .polyn"
- );
- printf(
- " file is useful for finding edges associated with input segments and forn"
- );
- printf(
- " setting boundary conditions in finite element simulations. Moreover,n");
- printf(
- " you will need the output .poly file if you plan to refine the outputn");
- printf(
- " mesh, and don't want segments to be missing in later triangulations.n");
- printf("n");
- printf(" .area files:n");
- printf(" First line: <# of triangles>n");
- printf(" Following lines: <triangle #> <maximum area>n");
- printf("n");
- printf(
- " An .area file associates with each triangle a maximum area that is usedn"
- );
- printf(
- " for mesh refinement. As with other file formats, every triangle mustn");
- printf(
- " be represented, and the triangles must be numbered consecutively. An");
- printf(
- " triangle may be left unconstrained by assigning it a negative maximumn");
- printf(" area.nn");
- printf(" .edge files:n");
- printf(" First line: <# of edges> <# of boundary markers (0 or 1)>n");
- printf(
- " Following lines: <edge #> <endpoint> <endpoint> [boundary marker]n");
- printf("n");
- printf(
- " Endpoints are indices into the corresponding .node file. Triangle cann"
- );
- printf(
- " produce .edge files (use the -e switch), but cannot read them. Then");
- printf(
- " optional column of boundary markers is suppressed by the -B switch.n");
- printf("n");
- printf(
- " In Voronoi diagrams, one also finds a special kind of edge that is ann");
- printf(
- " infinite ray with only one endpoint. For these edges, a differentn");
- printf(" format is used:nn");
- printf(" <edge #> <endpoint> -1 <direction x> <direction y>nn");
- printf(
- " The `direction' is a floating-point vector that indicates the directionn"
- );
- printf(" of the infinite ray.nn");
- printf(" .neigh files:n");
- printf(
- " First line: <# of triangles> <# of neighbors per triangle (always 3)>n"
- );
- printf(
- " Following lines: <triangle #> <neighbor> <neighbor> <neighbor>n");
- printf("n");
- printf(
- " Neighbors are indices into the corresponding .ele file. An index of -1n"
- );
- printf(
- " indicates no neighbor (because the triangle is on an exteriorn");
- printf(
- " boundary). The first neighbor of triangle i is opposite the firstn");
- printf(" corner of triangle i, and so on.nn");
- printf(
- " Triangle can produce .neigh files (use the -n switch), but cannot readn"
- );
- printf(" them.nn");
- printf("Boundary Markers:nn");
- printf(
- " Boundary markers are tags used mainly to identify which output verticesn");
- printf(
- " and edges are associated with which PSLG segment, and to identify whichn");
- printf(
- " vertices and edges occur on a boundary of the triangulation. A commonn");
- printf(
- " use is to determine where boundary conditions should be applied to an");
- printf(
- " finite element mesh. You can prevent boundary markers from being writtenn"
- );
- printf(" into files produced by Triangle by using the -B switch.nn");
- printf(
- " The boundary marker associated with each segment in an output .poly filen"
- );
- printf(" and each edge in an output .edge file is chosen as follows:n");
- printf(
- " - If an output edge is part or all of a PSLG segment with a nonzeron");
- printf(
- " boundary marker, then the edge is assigned the same marker.n");
- printf(
- " - Otherwise, if the edge lies on a boundary of the triangulationn");
- printf(
- " (even the boundary of a hole), then the edge is assigned the markern");
- printf(" one (1).n");
- printf(" - Otherwise, the edge is assigned the marker zero (0).n");
- printf(
- " The boundary marker associated with each vertex in an output .node filen");
- printf(" is chosen as follows:n");
- printf(
- " - If a vertex is assigned a nonzero boundary marker in the input file,n"
- );
- printf(
- " then it is assigned the same marker in the output .node file.n");
- printf(
- " - Otherwise, if the vertex lies on a PSLG segment (even if it is ann");
- printf(
- " endpoint of the segment) with a nonzero boundary marker, then then");
- printf(
- " vertex is assigned the same marker. If the vertex lies on severaln");
- printf(" such segments, one of the markers is chosen arbitrarily.n");
- printf(
- " - Otherwise, if the vertex occurs on a boundary of the triangulation,n");
- printf(" then the vertex is assigned the marker one (1).n");
- printf(" - Otherwise, the vertex is assigned the marker zero (0).n");
- printf("n");
- printf(
- " If you want Triangle to determine for you which vertices and edges are onn"
- );
- printf(
- " the boundary, assign them the boundary marker zero (or use no markers atn"
- );
- printf(
- " all) in your input files. In the output files, all boundary vertices,n");
- printf(" edges, and segments will be assigned the value one.nn");
- printf("Triangulation Iteration Numbers:nn");
- printf(
- " Because Triangle can read and refine its own triangulations, inputn");
- printf(
- " and output files have iteration numbers. For instance, Triangle mightn");
- printf(
- " read the files mesh.3.node, mesh.3.ele, and mesh.3.poly, refine then");
- printf(
- " triangulation, and output the files mesh.4.node, mesh.4.ele, andn");
- printf(" mesh.4.poly. Files with no iteration number are treated as ifn");
- printf(
- " their iteration number is zero; hence, Triangle might read the filen");
- printf(
- " points.node, triangulate it, and produce the files points.1.node andn");
- printf(" points.1.ele.nn");
- printf(
- " Iteration numbers allow you to create a sequence of successively finern");
- printf(
- " meshes suitable for multigrid methods. They also allow you to produce an"
- );
- printf(
- " sequence of meshes using error estimate-driven mesh refinement.n");
- printf("n");
- printf(
- " If you're not using refinement or quality meshing, and you don't liken");
- printf(
- " iteration numbers, use the -I switch to disable them. This switch alson");
- printf(
- " disables output of .node and .poly files to prevent your input files fromn"
- );
- printf(
- " being overwritten. (If the input is a .poly file that contains its ownn");
- printf(
- " points, a .node file is written. This can be quite convenient forn");
- printf(" computing CDTs or quality meshes.)nn");
- printf("Examples of How to Use Triangle:nn");
- printf(
- " `triangle dots' reads vertices from dots.node, and writes their Delaunayn"
- );
- printf(
- " triangulation to dots.1.node and dots.1.ele. (dots.1.node is identicaln");
- printf(
- " to dots.node.) `triangle -I dots' writes the triangulation to dots.elen");
- printf(
- " instead. (No additional .node file is needed, so none is written.)n");
- printf("n");
- printf(
- " `triangle -pe object.1' reads a PSLG from object.1.poly (and possiblyn");
- printf(
- " object.1.node, if the vertices are omitted from object.1.poly) and writesn"
- );
- printf(
- " its constrained Delaunay triangulation to object.2.node and object.2.ele.n"
- );
- printf(
- " The segments are copied to object.2.poly, and all edges are written ton");
- printf(" object.2.edge.nn");
- printf(
- " `triangle -pq31.5a.1 object' reads a PSLG from object.poly (and possiblyn"
- );
- printf(
- " object.node), generates a mesh whose angles are all between 31.5 and 117n"
- );
- printf(
- " degrees and whose triangles all have areas of 0.1 or less, and writes then"
- );
- printf(
- " mesh to object.1.node and object.1.ele. Each segment may be broken upn");
- printf(" into multiple subsegments; these are written to object.1.poly.n");
- printf("n");
- printf(
- " Here is a sample file `box.poly' describing a square with a square hole:n"
- );
- printf("n");
- printf(
- " # A box with eight vertices in 2D, no attributes, one boundary marker.n"
- );
- printf(" 8 2 0 1n");
- printf(" # Outer box has these vertices:n");
- printf(" 1 0 0 0n");
- printf(" 2 0 3 0n");
- printf(" 3 3 0 0n");
- printf(" 4 3 3 33 # A special marker for this vertex.n");
- printf(" # Inner square has these vertices:n");
- printf(" 5 1 1 0n");
- printf(" 6 1 2 0n");
- printf(" 7 2 1 0n");
- printf(" 8 2 2 0n");
- printf(" # Five segments with boundary markers.n");
- printf(" 5 1n");
- printf(" 1 1 2 5 # Left side of outer box.n");
- printf(" # Square hole has these segments:n");
- printf(" 2 5 7 0n");
- printf(" 3 7 8 0n");
- printf(" 4 8 6 10n");
- printf(" 5 6 5 0n");
- printf(" # One hole in the middle of the inner square.n");
- printf(" 1n");
- printf(" 1 1.5 1.5n");
- printf("n");
- printf(
- " Note that some segments are missing from the outer square, so you mustn");
- printf(
- " use the `-c' switch. After `triangle -pqc box.poly', here is the outputn"
- );
- printf(
- " file `box.1.node', with twelve vertices. The last four vertices weren");
- printf(
- " added to meet the angle constraint. Vertices 1, 2, and 9 have markersn");
- printf(
- " from segment 1. Vertices 6 and 8 have markers from segment 4. All then");
- printf(
- " other vertices but 4 have been marked to indicate that they lie on an");
- printf(" boundary.nn");
- printf(" 12 2 0 1n");
- printf(" 1 0 0 5n");
- printf(" 2 0 3 5n");
- printf(" 3 3 0 1n");
- printf(" 4 3 3 33n");
- printf(" 5 1 1 1n");
- printf(" 6 1 2 10n");
- printf(" 7 2 1 1n");
- printf(" 8 2 2 10n");
- printf(" 9 0 1.5 5n");
- printf(" 10 1.5 0 1n");
- printf(" 11 3 1.5 1n");
- printf(" 12 1.5 3 1n");
- printf(" # Generated by triangle -pqc box.polyn");
- printf("n");
- printf(" Here is the output file `box.1.ele', with twelve triangles.n");
- printf("n");
- printf(" 12 3 0n");
- printf(" 1 5 6 9n");
- printf(" 2 10 3 7n");
- printf(" 3 6 8 12n");
- printf(" 4 9 1 5n");
- printf(" 5 6 2 9n");
- printf(" 6 7 3 11n");
- printf(" 7 11 4 8n");
- printf(" 8 7 5 10n");
- printf(" 9 12 2 6n");
- printf(" 10 8 7 11n");
- printf(" 11 5 1 10n");
- printf(" 12 8 4 12n");
- printf(" # Generated by triangle -pqc box.polynn");
- printf(
- " Here is the output file `box.1.poly'. Note that segments have been addedn"
- );
- printf(
- " to represent the convex hull, and some segments have been subdivided byn");
- printf(
- " newly added vertices. Note also that <# of vertices> is set to zero ton");
- printf(" indicate that the vertices should be read from the .node file.n");
- printf("n");
- printf(" 0 2 0 1n");
- printf(" 12 1n");
- printf(" 1 1 9 5n");
- printf(" 2 5 7 1n");
- printf(" 3 8 7 1n");
- printf(" 4 6 8 10n");
- printf(" 5 5 6 1n");
- printf(" 6 3 10 1n");
- printf(" 7 4 11 1n");
- printf(" 8 2 12 1n");
- printf(" 9 9 2 5n");
- printf(" 10 10 1 1n");
- printf(" 11 11 3 1n");
- printf(" 12 12 4 1n");
- printf(" 1n");
- printf(" 1 1.5 1.5n");
- printf(" # Generated by triangle -pqc box.polyn");
- printf("n");
- printf("Refinement and Area Constraints:n");
- printf("n");
- printf(
- " The -r switch causes a mesh (.node and .ele files) to be read andn");
- printf(
- " refined. If the -p switch is also used, a .poly file is read and used ton"
- );
- printf(
- " specify edges that are constrained and cannot be eliminated (althoughn");
- printf(
- " they can be subdivided into smaller edges) by the refinement process.n");
- printf("n");
- printf(
- " When you refine a mesh, you generally want to impose tighter constraints.n"
- );
- printf(
- " One way to accomplish this is to use -q with a larger angle, or -an");
- printf(
- " followed by a smaller area than you used to generate the mesh you aren");
- printf(
- " refining. Another way to do this is to create an .area file, whichn");
- printf(
- " specifies a maximum area for each triangle, and use the -a switchn");
- printf(
- " (without a number following). Each triangle's area constraint is appliedn"
- );
- printf(
- " to that triangle. Area constraints tend to diffuse as the mesh isn");
- printf(
- " refined, so if there are large variations in area constraint betweenn");
- printf(
- " adjacent triangles, you may not get the results you want. In that case,n"
- );
- printf(
- " consider instead using the -u switch and writing a C procedure thatn");
- printf(" determines which triangles are too large.nn");
- printf(
- " If you are refining a mesh composed of linear (three-node) elements, then"
- );
- printf(
- " output mesh contains all the nodes present in the input mesh, in the samen"
- );
- printf(
- " order, with new nodes added at the end of the .node file. However, then");
- printf(
- " refinement is not hierarchical: there is no guarantee that each outputn");
- printf(
- " element is contained in a single input element. Often, an output elementn"
- );
- printf(
- " can overlap two or three input elements, and some input edges are notn");
- printf(
- " present in the output mesh. Hence, a sequence of refined meshes forms an"
- );
- printf(
- " hierarchy of nodes, but not a hierarchy of elements. If you refine an");
- printf(
- " mesh of higher-order elements, the hierarchical property applies only ton"
- );
- printf(
- " the nodes at the corners of an element; the midpoint nodes on each edgen");
- printf(" are discarded before the mesh is refined.nn");
- printf(
- " Maximum area constraints in .poly files operate differently from those inn"
- );
- printf(
- " .area files. A maximum area in a .poly file applies to the wholen");
- printf(
- " (segment-bounded) region in which a point falls, whereas a maximum arean");
- printf(
- " in an .area file applies to only one triangle. Area constraints in .polyn"
- );
- printf(
- " files are used only when a mesh is first generated, whereas arean");
- printf(
- " constraints in .area files are used only to refine an existing mesh, andn"
- );
- printf(
- " are typically based on a posteriori error estimates resulting from an");
- printf(" finite element simulation on that mesh.nn");
- printf(
- " `triangle -rq25 object.1' reads object.1.node and object.1.ele, thenn");
- printf(
- " refines the triangulation to enforce a 25 degree minimum angle, and thenn"
- );
- printf(
- " writes the refined triangulation to object.2.node and object.2.ele.n");
- printf("n");
- printf(
- " `triangle -rpaa6.2 z.3' reads z.3.node, z.3.ele, z.3.poly, and z.3.area.n"
- );
- printf(
- " After reconstructing the mesh and its subsegments, Triangle refines then");
- printf(
- " mesh so that no triangle has area greater than 6.2, and furthermore then");
- printf(
- " triangles satisfy the maximum area constraints in z.3.area. No anglen");
- printf(
- " bound is imposed at all. The output is written to z.4.node, z.4.ele, andn"
- );
- printf(" z.4.poly.nn");
- printf(
- " The sequence `triangle -qa1 x', `triangle -rqa.3 x.1', `triangle -rqa.1n");
- printf(
- " x.2' creates a sequence of successively finer meshes x.1, x.2, and x.3,n");
- printf(" suitable for multigrid.nn");
- printf("Convex Hulls and Mesh Boundaries:nn");
- printf(
- " If the input is a vertex set (not a PSLG), Triangle produces its convexn");
- printf(
- " hull as a by-product in the output .poly file if you use the -c switch.n");
- printf(
- " There are faster algorithms for finding a two-dimensional convex hulln");
- printf(" than triangulation, of course, but this one comes for free.nn");
- printf(
- " If the input is an unconstrained mesh (you are using the -r switch butn");
- printf(
- " not the -p switch), Triangle produces a list of its boundary edgesn");
- printf(
- " (including hole boundaries) as a by-product when you use the -c switch.n");
- printf(
- " If you also use the -p switch, the output .poly file contains all then");
- printf(" segments from the input .poly file as well.nn");
- printf("Voronoi Diagrams:nn");
- printf(
- " The -v switch produces a Voronoi diagram, in files suffixed .v.node andn");
- printf(
- " .v.edge. For example, `triangle -v points' reads points.node, producesn");
- printf(
- " its Delaunay triangulation in points.1.node and points.1.ele, andn");
- printf(
- " produces its Voronoi diagram in points.1.v.node and points.1.v.edge. Then"
- );
- printf(
- " .v.node file contains a list of all Voronoi vertices, and the .v.edgen");
- printf(
- " file contains a list of all Voronoi edges, some of which may be infiniten"
- );
- printf(
- " rays. (The choice of filenames makes it easy to run the set of Voronoin");
- printf(" vertices through Triangle, if so desired.)nn");
- printf(
- " This implementation does not use exact arithmetic to compute the Voronoin"
- );
- printf(
- " vertices, and does not check whether neighboring vertices are identical.n"
- );
- printf(
- " Be forewarned that if the Delaunay triangulation is degenerate orn");
- printf(
- " near-degenerate, the Voronoi diagram may have duplicate vertices orn");
- printf(" crossing edges.nn");
- printf(
- " The result is a valid Voronoi diagram only if Triangle's output is a truen"
- );
- printf(
- " Delaunay triangulation. The Voronoi output is usually meaningless (andn");
- printf(
- " may contain crossing edges and other pathology) if the output is a CDT orn"
- );
- printf(
- " CCDT, or if it has holes or concavities. If the triangulated domain isn");
- printf(
- " convex and has no holes, you can use -D switch to force Triangle ton");
- printf(
- " construct a conforming Delaunay triangulation instead of a CCDT, so then");
- printf(" Voronoi diagram will be valid.nn");
- printf("Mesh Topology:nn");
- printf(
- " You may wish to know which triangles are adjacent to a certain Delaunayn");
- printf(
- " edge in an .edge file, which Voronoi cells are adjacent to a certainn");
- printf(
- " Voronoi edge in a .v.edge file, or which Voronoi cells are adjacent ton");
- printf(
- " each other. All of this information can be found by cross-referencingn");
- printf(
- " output files with the recollection that the Delaunay triangulation andn");
- printf(" the Voronoi diagram are planar duals.nn");
- printf(
- " Specifically, edge i of an .edge file is the dual of Voronoi edge i ofn");
- printf(
- " the corresponding .v.edge file, and is rotated 90 degrees counterclock-n");
- printf(
- " wise from the Voronoi edge. Triangle j of an .ele file is the dual ofn");
- printf(
- " vertex j of the corresponding .v.node file. Voronoi cell k is the dualn");
- printf(" of vertex k of the corresponding .node file.nn");
- printf(
- " Hence, to find the triangles adjacent to a Delaunay edge, look at then");
- printf(
- " vertices of the corresponding Voronoi edge. If the endpoints of an");
- printf(
- " Voronoi edge are Voronoi vertices 2 and 6 respectively, then triangles 2n"
- );
- printf(
- " and 6 adjoin the left and right sides of the corresponding Delaunay edge,n"
- );
- printf(
- " respectively. To find the Voronoi cells adjacent to a Voronoi edge, lookn"
- );
- printf(
- " at the endpoints of the corresponding Delaunay edge. If the endpoints ofn"
- );
- printf(
- " a Delaunay edge are input vertices 7 and 12, then Voronoi cells 7 and 12n"
- );
- printf(
- " adjoin the right and left sides of the corresponding Voronoi edge,n");
- printf(
- " respectively. To find which Voronoi cells are adjacent to each other,n");
- printf(" just read the list of Delaunay edges.nn");
- printf(
- " Triangle does not write a list of the edges adjoining each Voronoi cell,n"
- );
- printf(
- " but you can reconstructed it straightforwardly. For instance, to findn");
- printf(
- " all the edges of Voronoi cell 1, search the output .edge file for everyn");
- printf(
- " edge that has input vertex 1 as an endpoint. The corresponding dualn");
- printf(
- " edges in the output .v.edge file form the boundary of Voronoi cell 1.n");
- printf("n");
- printf(
- " For each Voronoi vertex, the .neigh file gives a list of the threen");
- printf(
- " Voronoi vertices attached to it. You might find this more convenientn");
- printf(" than the .v.edge file.nn");
- printf("Quadratic Elements:nn");
- printf(
- " Triangle generates meshes with subparametric quadratic elements if then");
- printf(
- " -o2 switch is specified. Quadratic elements have six nodes per element,n"
- );
- printf(
- " rather than three. `Subparametric' means that the edges of the trianglesn"
- );
- printf(
- " are always straight, so that subparametric quadratic elements aren");
- printf(
- " geometrically identical to linear elements, even though they can be usedn"
- );
- printf(
- " with quadratic interpolating functions. The three extra nodes of ann");
- printf(
- " element fall at the midpoints of the three edges, with the fourth, fifth,n"
- );
- printf(
- " and sixth nodes appearing opposite the first, second, and third cornersn");
- printf(" respectively.nn");
- printf("Domains with Small Angles:nn");
- printf(
- " If two input segments adjoin each other at a small angle, clearly the -qn"
- );
- printf(
- " switch cannot remove the small angle. Moreover, Triangle may have non");
- printf(
- " choice but to generate additional triangles whose smallest angles aren");
- printf(
- " smaller than the specified bound. However, these triangles only appearn");
- printf(
- " between input segments separated by small angles. Moreover, if youn");
- printf(
- " request a minimum angle of theta degrees, Triangle will generally producen"
- );
- printf(
- " no angle larger than 180 - 2 theta, even if it is forced to compromise onn"
- );
- printf(" the minimum angle.nn");
- printf("Statistics:nn");
- printf(
- " After generating a mesh, Triangle prints a count of entities in then");
- printf(
- " output mesh, including the number of vertices, triangles, edges, exteriorn"
- );
- printf(
- " boundary edges (i.e. subsegments on the boundary of the triangulation,n");
- printf(
- " including hole boundaries), interior boundary edges (i.e. subsegments ofn"
- );
- printf(
- " input segments not on the boundary), and total subsegments. If you'ven");
- printf(
- " forgotten the statistics for an existing mesh, run Triangle on that meshn"
- );
- printf(
- " with the -rNEP switches to read the mesh and print the statistics withoutn"
- );
- printf(
- " writing any files. Use -rpNEP if you've got a .poly file for the mesh.n");
- printf("n");
- printf(
- " The -V switch produces extended statistics, including a rough estimaten");
- printf(
- " of memory use, the number of calls to geometric predicates, andn");
- printf(
- " histograms of the angles and the aspect ratios of the triangles in then");
- printf(" mesh.nn");
- printf("Exact Arithmetic:nn");
- printf(
- " Triangle uses adaptive exact arithmetic to perform what computationaln");
- printf(
- " geometers call the `orientation' and `incircle' tests. If the floating-n"
- );
- printf(
- " point arithmetic of your machine conforms to the IEEE 754 standard (asn");
- printf(
- " most workstations do), and does not use extended precision internaln");
- printf(
- " floating-point registers, then your output is guaranteed to be ann");
- printf(
- " absolutely true Delaunay or constrained Delaunay triangulation, roundoffn"
- );
- printf(
- " error notwithstanding. The word `adaptive' implies that these arithmeticn"
- );
- printf(
- " routines compute the result only to the precision necessary to guaranteen"
- );
- printf(
- " correctness, so they are usually nearly as fast as their approximaten");
- printf(" counterparts.nn");
- printf(
- " May CPUs, including Intel x86 processors, have extended precisionn");
- printf(
- " floating-point registers. These must be reconfigured so their precisionn"
- );
- printf(
- " is reduced to memory precision. Triangle does this if it is compiledn");
- printf(" correctly. See the makefile for details.nn");
- printf(
- " The exact tests can be disabled with the -X switch. On most inputs, thisn"
- );
- printf(
- " switch reduces the computation time by about eight percent--it's notn");
- printf(
- " worth the risk. There are rare difficult inputs (having many collinearn");
- printf(
- " and cocircular vertices), however, for which the difference in speedn");
- printf(
- " could be a factor of two. Be forewarned that these are precisely then");
- printf(
- " inputs most likely to cause errors if you use the -X switch. Hence, then"
- );
- printf(" -X switch is not recommended.nn");
- printf(
- " Unfortunately, the exact tests don't solve every numerical problem.n");
- printf(
- " Exact arithmetic is not used to compute the positions of new vertices,n");
- printf(
- " because the bit complexity of vertex coordinates would grow withoutn");
- printf(
- " bound. Hence, segment intersections aren't computed exactly; in veryn");
- printf(
- " unusual cases, roundoff error in computing an intersection point mightn");
- printf(
- " actually lead to an inverted triangle and an invalid triangulation.n");
- printf(
- " (This is one reason to specify your own intersection points in your .polyn"
- );
- printf(
- " files.) Similarly, exact arithmetic is not used to compute the verticesn"
- );
- printf(" of the Voronoi diagram.nn");
- printf(
- " Another pair of problems not solved by the exact arithmetic routines isn");
- printf(
- " underflow and overflow. If Triangle is compiled for double precisionn");
- printf(
- " arithmetic, I believe that Triangle's geometric predicates work correctlyn"
- );
- printf(
- " if the exponent of every input coordinate falls in the range [-148, 201].n"
- );
- printf(
- " Underflow can silently prevent the orientation and incircle tests fromn");
- printf(
- " being performed exactly, while overflow typically causes a floatingn");
- printf(" exception.nn");
- printf("Calling Triangle from Another Program:nn");
- printf(" Read the file triangle.h for details.nn");
- printf("Troubleshooting:nn");
- printf(" Please read this section before mailing me bugs.nn");
- printf(" `My output mesh has no triangles!'nn");
- printf(
- " If you're using a PSLG, you've probably failed to specify a proper setn"
- );
- printf(
- " of bounding segments, or forgotten to use the -c switch. Or you mayn");
- printf(
- " have placed a hole badly, thereby eating all your triangles. To testn");
- printf(" these possibilities, try again with the -c and -O switches.n");
- printf(
- " Alternatively, all your input vertices may be collinear, in which casen"
- );
- printf(" you can hardly expect to triangulate them.nn");
- printf(" `Triangle doesn't terminate, or just crashes.'nn");
- printf(
- " Bad things can happen when triangles get so small that the distancen");
- printf(
- " between their vertices isn't much larger than the precision of yourn");
- printf(
- " machine's arithmetic. If you've compiled Triangle for single-precisionn"
- );
- printf(
- " arithmetic, you might do better by recompiling it for double-precision.n"
- );
- printf(
- " Then again, you might just have to settle for more lenient constraintsn"
- );
- printf(
- " on the minimum angle and the maximum area than you had planned.n");
- printf("n");
- printf(
- " You can minimize precision problems by ensuring that the origin liesn");
- printf(
- " inside your vertex set, or even inside the densest part of yourn");
- printf(
- " mesh. If you're triangulating an object whose x-coordinates all falln");
- printf(
- " between 6247133 and 6247134, you're not leaving much floating-pointn");
- printf(" precision for Triangle to work with.nn");
- printf(
- " Precision problems can occur covertly if the input PSLG contains twon");
- printf(
- " segments that meet (or intersect) at an extremely small angle, or ifn");
- printf(
- " such an angle is introduced by the -c switch. If you don't realizen");
- printf(
- " that a tiny angle is being formed, you might never discover whyn");
- printf(
- " Triangle is crashing. To check for this possibility, use the -S switchn"
- );
- printf(
- " (with an appropriate limit on the number of Steiner points, found byn");
- printf(
- " trial-and-error) to stop Triangle early, and view the output .poly filen"
- );
- printf(
- " with Show Me (described below). Look carefully for regions where densen"
- );
- printf(
- " clusters of vertices are forming and for small angles between segments.n"
- );
- printf(
- " Zoom in closely, as such segments might look like a single segment fromn"
- );
- printf(" a distance.nn");
- printf(
- " If some of the input values are too large, Triangle may suffer an");
- printf(
- " floating exception due to overflow when attempting to perform ann");
- printf(
- " orientation or incircle test. (Read the section on exact arithmeticn");
- printf(
- " above.) Again, I recommend compiling Triangle for double (rathern");
- printf(" than single) precision arithmetic.nn");
- printf(
- " Unexpected problems can arise if you use quality meshing (-q, -a, orn");
- printf(
- " -u) with an input that is not segment-bounded--that is, if your inputn");
- printf(
- " is a vertex set, or you're using the -c switch. If the convex hull ofn"
- );
- printf(
- " your input vertices has collinear vertices on its boundary, an inputn");
- printf(
- " vertex that you think lies on the convex hull might actually lie justn");
- printf(
- " inside the convex hull. If so, the vertex and the nearby convex hulln");
- printf(
- " edge form an extremely thin triangle. When Triangle tries to refinen");
- printf(
- " the mesh to enforce angle and area constraints, Triangle might generaten"
- );
- printf(
- " extremely tiny triangles, or it might fail because of insufficientn");
- printf(" floating-point precision.nn");
- printf(
- " `The numbering of the output vertices doesn't match the input vertices.'n"
- );
- printf("n");
- printf(
- " You may have had duplicate input vertices, or you may have eaten somen");
- printf(
- " of your input vertices with a hole, or by placing them outside the arean"
- );
- printf(
- " enclosed by segments. In any case, you can solve the problem by notn");
- printf(" using the -j switch.nn");
- printf(
- " `Triangle executes without incident, but when I look at the resultingn");
- printf(
- " mesh, it has overlapping triangles or other geometric inconsistencies.'n");
- printf("n");
- printf(
- " If you select the -X switch, Triangle occasionally makes mistakes duen");
- printf(
- " to floating-point roundoff error. Although these errors are rare,n");
- printf(
- " don't use the -X switch. If you still have problems, please report then"
- );
- printf(" bug.nn");
- printf(
- " `Triangle executes without incident, but when I look at the resultingn");
- printf(" Voronoi diagram, it has overlapping edges or other geometricn");
- printf(" inconsistencies.'n");
- printf("n");
- printf(
- " If your input is a PSLG (-p), you can only expect a meaningful Voronoin"
- );
- printf(
- " diagram if the domain you are triangulating is convex and free ofn");
- printf(
- " holes, and you use the -D switch to construct a conforming Delaunayn");
- printf(" triangulation (instead of a CDT or CCDT).nn");
- printf(
- " Strange things can happen if you've taken liberties with your PSLG. Don");
- printf(
- " you have a vertex lying in the middle of a segment? Triangle sometimesn");
- printf(
- " copes poorly with that sort of thing. Do you want to lay out a collinearn"
- );
- printf(
- " row of evenly spaced, segment-connected vertices? Have you simplyn");
- printf(
- " defined one long segment connecting the leftmost vertex to the rightmostn"
- );
- printf(
- " vertex, and a bunch of vertices lying along it? This method occasionallyn"
- );
- printf(
- " works, especially with horizontal and vertical lines, but often itn");
- printf(
- " doesn't, and you'll have to connect each adjacent pair of vertices with an"
- );
- printf(" separate segment. If you don't like it, tough.nn");
- printf(
- " Furthermore, if you have segments that intersect other than at theirn");
- printf(
- " endpoints, try not to let the intersections fall extremely close to PSLGn"
- );
- printf(" vertices or each other.nn");
- printf(
- " If you have problems refining a triangulation not produced by Triangle:n");
- printf(
- " Are you sure the triangulation is geometrically valid? Is it formattedn");
- printf(
- " correctly for Triangle? Are the triangles all listed so the first threen"
- );
- printf(
- " vertices are their corners in counterclockwise order? Are all of then");
- printf(
- " triangles constrained Delaunay? Triangle's Delaunay refinement algorithmn"
- );
- printf(" assumes that it starts with a CDT.nn");
- printf("Show Me:nn");
- printf(
- " Triangle comes with a separate program named `Show Me', whose primaryn");
- printf(
- " purpose is to draw meshes on your screen or in PostScript. Its secondaryn"
- );
- printf(
- " purpose is to check the validity of your input files, and do so moren");
- printf(
- " thoroughly than Triangle does. Unlike Triangle, Show Me requires thatn");
- printf(
- " you have the X Windows system. Sorry, Microsoft Windows users.n");
- printf("n");
- printf("Triangle on the Web:n");
- printf("n");
- printf(" To see an illustrated version of these instructions, check outn");
- printf("n");
- printf(" http://www.cs.cmu.edu/~quake/triangle.htmln");
- printf("n");
- printf("A Brief Plea:n");
- printf("n");
- printf(
- " If you use Triangle, and especially if you use it to accomplish realn");
- printf(
- " work, I would like very much to hear from you. A short letter or emailn");
- printf(
- " (to jrs@cs.berkeley.edu) describing how you use Triangle will mean a lotn"