[N-World Contents] [Book Contents] [Prev] [Next] [Index]

Appendix A ASCII Object
File Format

Objects created on modeling systems other than N-Geometry can be read into N-Geometry if their data files are converted to a format N-Geometry understands. Some familiarity with the N-Geometry object structure and the body classes is useful in helping to understand the file organization. Depending on the saveout mode, the following information may be maintained in one file or in three smaller files (see below).

N-Geometry object files are always text files consisting of keyword and value pairs, and mirror the structure of the objects themselves. The file is of the type :object, whose extension is .geo. A file represents one object, but that object may be either a simple object, with a single body as its inferior, or the top of an arbitrarily complex hierarchy of objects.

The hierarchical structure of objects is represented in the file as an outline structure. Each of the different object and body classes, as well as the body-display-items, has its own file-writing routine, and as the object hierarchy is traversed, each is passed the output stream to add its contribution. The result is a nested structure, with information from the top-level object surrounding that of any subobjects, which in turn enclose bdi information, which surround the basic body data section.

This structure is read by different classes as they are instanced on readin, thus keywords relevant to a body must always appear inside the body section. Body-specific keywords outside the body section will be ignored, and conversely, object keywords (for example) appearing inside the body section are ignored.

An object file consists of three basic parts, two of which are optional:

The File Attribute Header

This is always kept in the file filename.geo.

The file optionally begins with the following file attribute line, which is inserted solely for ease of editing in Xemacs:

;;; -*- Base: 10.; Lowercase: Yes; Mode: Lisp; Package: 3d;-*-

Whether or not this attribute line is here, N-Geometry assumes all integers are base 10, and the current package is the GEOMETRY (3D) package.

Note. Symbols in other packages should be made explicit.

Readin Information

This is always kept in the file foo.geo.

Readin information is optional data not connected with any object or body, and helps define the readin environment. Two such keywords are currently recognized in N-Geometry:

:version

Keyword, specifies the major version number of the copy of N-Geometry that wrote the file. It is not meaningful for files produced by other means.

:units

Keyword, Specifies the real-world units that the numbers in this file are presumed to represent. If, on readin, the units are not the same as the current global units, the object will be scaled to preserve the proper relative size. If they are not here, the file will be read in in whatever the current global units are, which can lead to problems trying to recreate a scen when the objects were made at different times or on different machines using different units.

Object Specification

This is always kept in the file filename.geo.

The bulk of the file consists of the object specification for the top-level object, but the basic structure applies also to subobjects. The format of an object specification consists of delimiters and the object description, as follows:

:name <"object name">

	<object description>

:end <"object name" (optional)>

The :name keyword begins the object specification.

<object name> must be a string (bounded by double-quotation marks).

:end concludes an object description. N-Geometry typically writes the name string after an :end keyword, but it is optional and included only to make the file easier to read.

Object Description

This is always kept in the file filename.geo.

The object description consists of a number of different keyword-value pairs, but the only required component inside an object description is a :body specification, which will specify the body of the object, and whether it is a list of more objects or a single geometric entity.

The basic structure of the object description is as follows:

<object information (optional)>

:body <body identifier>

<body description>

<object information (optional)>

Body Identifiers

The body identifier, the value for the :body keyword, can be a symbol, a string, or a list.

The Symbolic Body Identifier

If the body identifier is a symbol, it can represent one of three things, which are checked in the following order:

1. A class name.

This will cause a body of that flavor to be created, and the open file handed off to that body to read. What follows in the file is specific to that flavor. In the example below, the restored body will be a polyhedron, and the section following (up to the :end-body keyword) contains polyhedron-specific information (described later).

Note. All :end-xxx keywords are treated interchangeably and are differentiated only to make the file clearer to read.
:body POLYHEDRON

:description "(Polyhedron):    4pts    6edges    4faces

:vertices

((0.0						  30.48				0.0)

  (0.		0				-10.16				28.73682)

  (24.886818						-10.16				-14.36841)

  (-24.886818						-10.16				-14.36841))

:edges

((1			3)

  (3			2)

  (2			1)

  (2			4)

  (4			1)

  (4			3)

:faces-by-edge

((1			2	3)

  (3			4	5)

  (5			6	1)

  (2			6	4)

:end-body "POLYHEDRON"

2. A group (or a list, which is treated identically).

This indicates that what follows in the file is a series of object specifications, representing another layer in the object hierarchy. It is terminated by an :end or :end-body keyword.

Note. The indentation which N-Geometry typically used to write out an object is completely optional and has no effect on reading the file.
:body GROUP

	:name "My Tetrahedron"

	:body <body>

	<body-description>

	:end "My Tetrahedron"

	:name "My cube

	:body <body>

	<body-description>

	:end "My Cube"

:end-body "GROUP"

3. Another special symbol which yields a body.

Currently, the only other such symbol recognized by N-Geometry is
BODY-FILE, which indicates that what follows is a pathname where a separate file describing the body in full may be found. It is assumed that no further body information is in the object file, and that the :end-body is implicit in the end of the body file, so that keyword should not appear here. This is currently only used by the binary body facility. For example, the above polyhedron written into a binary body file would yield the following object description:

:body BODY-FILE 			(:DUCK "SNAKE" :U

			("delrey:" "people" "caro" "geodoc" "bodies")

			  "Tetrahedron 3PVGJ4" :BODY :U)

String Body Identifier

This information can also be in foo<code>.tbd, where <code> is an automatically generated timestamp.

If the body identifier is a string, the string refers to the name of another object previously encountered in the same file with that name. This requires the obect in the file to be a multiple object. The object so referenced will be reinstanced upon readin. Inasmuch as the reinstanced bodies are the same, there should be no body description. That is, no further body information, and no :end-body keyword should be written.

The following example illustrates:

:body GROUP

	:name "My Tetrahedron"

	:matrix (1 0 0   0 1 0   0 0 1   0 0 0)

	:body BODY-FILE    (:DUCK "SNAKE" :U

		("delrey:" "people" "caro" "geodoc" "bodies")

		  "Tetrahedron 3PVGJ4" :BODY :U)

	:end "My Tetrahedron"

	:name "My Tetrahedron<2>"

	:matrix (1 0 0   					0 1 0   0 0 1   -2 0 0)

	:body "My Tetrahedron"

	:end "My Tetrahedron<2>"

	:name "My Tetrahedron<3>"

	:matrix (1 0 0   0 1 0   0 0 1   2 0 0)

	:body "My Tetrahedron"

	:end "My Tetrahedron<3>"

:end-body GROUP

This represents a group of three tetrahedra, all referencing the one body found in the specified body file. The :matrix object keyword here indicates that, although they share the same body, the three objects appear in different positions. The first is in its home position, the second is displaced two units left (along the negative x axis), the third, 2 units right.

List Body Identifier

If the body identifier is a list, the body identifier is assumed to be an expression that when evaluated returns a body. For example, our tetrahedron body could have been written as follows:

:body (make-tetrahedron 1.0)

:end-body "tetrahedron"

The 3D:MAKE-TETRAHEDRON function returns a fully-formed polyhedron. Note that the form (make-instance `body-class) is exactly equivalent to just using the flavor symbol body-class.

Optional Object Information

This is always kept in the file filename.geo.

:matrix

Sets the initial transformation of the object. The value of this keyword is a list of 12, 16, or 17 elements, which are used to set the object's initial transformation.

If of length 12, the list is assumed to represent a 3x4 matrix is row-major order:

1			2		3

4			5		6

7			8		9

10			11		12

If of length 16, the elements represent a 4x4 matrix:

1			2		3		4

5			6		7		8

9			10		11		12

13			14		15		16

A 17-element list is identical to a 16 element list, with the exception that the first element is ignored. N-Geometry has traditionally written out an integer code as the first item in the matrix list, but is is not used on readin and need not be included.

:documentation

Used to help identify the origin or use of the object. The value of this keyword is a string of any length that is stored with the object but is otherwise ignored on readin.

:view-relative

Makes the object into a view-relative object if the value of this keyword is anything non-nil. Its initial position, as described by the :matrix keyword, is interpreted as being in the frame of reference of the camera.

:init-display

Used by N-Geometry to save the display state of each terminal object at writeout time. It should not be included in files created from other sources. This is actually output by body display items, so it occurs only in the object description of terminal objects (those whose body is a simple geometric entity).

Body Keywords

This information can be kept in the file foo.geo or foo<code>.tbd, where <code> is an automatically generated timestamp.

These keywords are relevant to bodies of any flavor:

:version

Specifies the major version number of the copy of N-Geometry writing this file. Optional.

:description

Specifies the type and number of elements that make up the body. This keyword primarily makes it easier to read the file; in the case of polyhedra, N-Geometry does refer to it to help speed up readin. This keyword's presence is not mandatory; if you do use it, you must use the following format:

"(<flavor-name>): <nv>pts <ne>edges <nf>faces {<np>parts}"

The curly braces indicate that the parts specifier is optional.

:eval

Is an expression that is evaluated inside the body instance when it is read in. Because it is evaluated inside the instance, instance-variables, such as SELF, are directly accessible. This allows you to store operations that create a large volume of data in algorithmic form, thus saving both file size and readin time. For instance, you could save a smoothed polyhedron by saving the explicit geometry of the unsmoothed version, which is relatively compact, and then include the following:

:eval (doo-smooth self .5 :npasses 3)

Keyword Any eternal property

If you have defined this keyword as an eternal, or saveable property for the flavor of body being read (for a list, call 3D:ALL-ETERNAL-PROPERTIES-FOR-ELEMENT), the value of this keyword is added to the body's property list. Keyword and symbols in the geometry package are treated equvalently. For example, the following puts the NLATITUDES property on the body:

:nlatitudes 18

Any operation

If the keyword is a message or generic function (a non-keyword symbol) that this body flavor handles, the body is sent the message with the value of the keyword (which must be a list or nil) as arguments. You could save the above example for :eval simply as follows:

:doo-smooth (.5 :npasses 3)

Polyhedron Keywords

This information can be stored in either foo.geo or foo<>.tbd.

Keywords of this type are handled only by bodies of flavor 3D:polyhedron.

For the following entries with two choices, the element lists of the
"numbered-" variants are assumed to have one extra element, the first, which is an integer serial number. Normally N-Geometry ignores this number and assumes the elements are numbered consecutivel starting with 1, so this option is used primarily for ease of perusing the file. You can, however, request N-Geometry to actually read the numbers and use them as serial numbers.

:vertices

:numbered-vertices

Specifies a list of three-element lists of the xyz coordinates of a polyhedron's vertices, as follows:

((<x-coordinate>      <y-coordinate>      <z-coordinate>)

...)

:vertex-attributes

Specifies as association list of vertex attributes and the serial numbers of the vertices to which they belong.

:edges

:numbered-edges

Specifies a list of two-element lists of the endpoints of a polyhedron's edges. The numbers refer to the serial numbers of the vertices in the :vertices list, above. Because of this dependence, the :vertices list must always preced the :edges list in the file:

((<head-vtx>      <tail-vtx>)

...)

:faces-by-edge
:numbered-faces-by-edge

Specifies a list of n-element lists, containing the serial numbers of the edges bounding each face. The edges are traced in clockwise order fromthe outside of the polyhedron. Because of the dependence on the edge serial numbers, the :edges list must always preced the :faces-by-edge list in the file:

((<first-edge>  <second-edge>  <third-edge>...<nth-edge>)

...)

:faces-by-vertex
:numbered-faces-by-vertex

Specifies a list of n-element lists, containing the serial numbers of the vertices of each face, in clockwise order from the outside of the polyhedron. Because of the dependence on the vertex serial numbers, the :vertices list must always precede the :faces-by-vertex list in the file.

Also, there should be no :edges list, which is one of the primary advantages of using this keyword over the :faces-by-edge keyword; the file takes up less space. Another advantage is that some other systems describe polygons by their vertices, so it becomes easier to convert file formats to and from such systems. Because edges are shared by neighboring faces, however, the database must be searched for existing edges as pairs of vertices are read in, making this method somewhat more time consuming than using :faces-by-edge.

The following illustrates the faces-by-vertex construct:

((<first-vtx>  <second-vtx>  <third-vtx>...<nth-vtx>)

...)

Keyword :face-attributes

Specifies an association list of face attributes and the serial numbers of the faces to which they belong.

:attributes

Specifies the polyhedron's render attribute list. A description of the elements of this, as well as the face- and vertex-attributes lists, is the province of N-Render and is not covered in this discussion.

:parts

Follows any of the above element-reading keywords in the file; is applicable to any bodies containing 3D:parts-mixin. The value is a list of three-element lists, each consisting of a part name (a string), a single-member list of the flavor of the part components, and a list of the serial numbers of the part components:

((<name-of-part-1>  <flavor-of-elements>  
<element-serial-numbers>
...)

The following example illustrates the parts format:

(("Part of 5 faces"    (FACE)    (1 5 32 6 20))
("Top face vertices" (VERTEX) (120 121 122 123)))

:locus-state-lists

There are two entries here, both of which are displacements:

:locus-state-lists and :displacements. Assuming they are non-nil, both are lists that look like:

((displacement-name-1

  (vnum-1 dx dy dz)

  (vnum-2 dx dy dz)

  ...)

 (displacement-name-2

   ...))

Vnums are indices into the vertex lists. The only difference is that in the locus-state lists the dx dy dz are absolute coordinates while in the displacement lists they are relative offsets.

Displacement lists may also have an axis at the end of the list if they are rotational displacements.

(The :locus-state-lists property gets written out even when there aren't any, which is why you get the () following the keyword.)


Saving Objects

When saving objects in the native .geo format, you have three methods to save an object:

Note that these options all apply to the native geometry (.geo) format. Objects saved in the Wavefront (.obj) file format are always saved as single text files.

When you use either the second or third option for saving a geo object, three files are created:

The .geo file references the .body file, and the .body file references the .tbd or the .bbd file. This structure facilitates the reinstancing of an object.

Also, as long as the only difference between multiple objects is tranformational (rather than topological), multiple objects can reference the same body data file, which saves disk space. While this may not be significant for some users, it can be critical for people working with databases with tens of thousands of vertices, such as those generated by three-dimensional scanners.

Typically the .body and .tbd or .bbd files are saved in a /bodies subdirectory of the N-Geometry directory (although this can be modified from within the N-Geometry user interface).

Saving a Sample Object

A typical .geo file (in this case, for a tetrahedron) would look something like this:

;;; -*- Base: 10.; Lowercase: Yes; Mode: Lisp; Syntax: CLtL; Package: 3d; -*-

(in-package "3D")

:version (100 0)

:units FEET

:name "Tetrahedron"

:init-display (:visible-p t :backface-culling-p t  
:min-edge-hardness nil)

:body BODY-FILE (:DUCK "SNAKE" :U

			("delrey1" "people" "caro" "geodoc" "bodies")

			  "Tetrahedron3PVGJ4" :BODY :U)

:end "Tetrahedron"

(EOF)

The corresponding .body file would look something like this:

POLYHEDRON

Tetrahedron3PVGJ4

(:DUCK "SNAKE" :U ("delrey1" "people" "caro" "geodoc") "Tetrahedron" :OBJECT :U) :BINARY-BODYDATA :UNSPECIFIC

(EOF)

Finally, if the body data were saved in a text format, the corresponding .tbd file would look something like this:

:body POLYHEDRON

:version (100 0)

:description "(Polyhedron): 15pts 28edges 15faces."

:numbered-vertices

((1	-1.9096849	13.180311	-1.1025571)

 (2	0.0	-3.3333335	9.42809)

 (3 	8.164966	-3.3333335	-4.714047)

 (4 	-8.164966	-3.3333335	-4.714047)

 (5 	5.4120126	-3.6708906	12.552714)

 (6 	2.758126	11.126 	1.5924047)

 (7 	13.576978	-3.6708906	-1.5894197)

 (8 	1.6329931	7.333333	-0.9428094)

 (9 	0.5516252	10.2252	0.31848094)

 (10	-1.6329931	7.333333	-0.9428094)

 (11	0.0    	7.333333	1.8856181)

 (12	2.758126	-2.0187716	10.88716)

 (13	2.5948267	-2.2740002	10.926212)

 (14	10.759792	-2.2740002	-3.2159228)

 (15	10.807622	-2.0187716	-3.0549753))

:numbered-faces-by-vertex

((1	 	6	15	12)

 (2	 	10	11	2	4)

 (3	 	8	10	4	3)

 (4	 	2	3	4)

 (5	 	11	9	6	12	13	2)

 (6	 	9	8	3	14	15	6)

 (7	 	3	2	13	14)

 (8	 	8	9	1)

 (9	 	10	8	1)

 (10		11	10	1)

 (11		9	11	1)

 (12		5	13	12)

 (13		7	15	14)

 (14			13	5		7	14)

 (15			5	12		15	7))

:locus-state-lists

 (  )

:end-body "POLYHEDRON"

(EOF)

The .tbd file contains only topological information, along with the vertex coordinates of the object in its untransformed state.

Note that if you change an object's topology (extruding a face, for instance), and then save it, the .tbd or .bbd file is updated automatically (without baking).



[N-World Contents] [Book Contents] [Prev] [Next] [Index]

Another fine product from Nichimen documentation!

Copyright © 1996, Nichimen Graphics Corporation. All rights reserved.