570 likes | 683 Vues
Computer Graphics - Chapter 4 Geometric Objects and Transformations. Objectives are to learn to: represent the basic geometric types learn to convert between various representations learn to establish a method for dealing with geometric problems that are independent of coordinate systems.
E N D
Computer Graphics - Chapter 4 Geometric Objects and Transformations • Objectives are to learn to: • represent the basic geometric types • learn to convert between various representations • learn to establish a method for dealing with geometric problems that are independent of coordinate systems. • Much of what we present in this chapter is an application of vector spaces, geometry, and linear algebra. Chapter (4)
The Geometric View We can define most geometric objects using a limited set of simple entities. Three basic types are needed: 1) scalars, 2) points, and 3) vectors. These entities can be defined in at least three different ways: 1) from a mathematical perspective, 2) from a programming perspective, or 3) from a geometric perspective. The fundamental geometric object is a point. In 3-D a point is a location in the space. The only attribute a point assumes is its location. Scalars do not have geometric properties and are used as units of measurement. In computer graphics, we connect points with directed line segments, vectors. A vector does not have a fixed position. Chapter (4)
The Geometric View – cont. Mathematician like to see things as points, scalars, and vectors. Computer scientists like to see them as abstract data types (ADTs). An ADT is a set of operations on data. These operations are defined independently of how the data are represented internally or of how the operations are implemented. Chapter (4)
Geometric ADTs Subtraction of two points will result in a vector: v = P – Q This also can be written as: P = Q + v Some other possibilities are shown below. Head_to_tail rule for vectors Head_to_tail rule for points P - Q P-R Q - R Chapter (4)
Lines A line can be represented as: Where P0 is an arbitrary point, d is an arbitrary vector, and is a scalar. You have seen a similar thing for line before as: y = b + mx. Affine Sums In an affine space, the addition of two vectors the multiplication of a vector by a scalar, and the addition of a vector and a point are defined. the addition of two arbitrary points multiplication of a point by a scalar are not defined. Find a point such that: Thus, This looks like addition of 2 points, where Chapter (4)
Convexity A convex object is one for which any point lying on the line segment connecting any two points in the object is also in the object. For , the affine sum defines the line segment connecting R and Q, as shown in this figure. This line is convex object. We can extend the affine sum to include objects defined by n points P1, P2, …,Pn. Something like this: We can use induction to show that this line is defined if and only if (iff): A set of points formed by the affine sum of n points, under the restriction: is called the convex hull of the set of points. It is the smallest convex object that includes the set of points. The convex hull includes all line segments connecting pairs of points in {P1, P2, …,Pn}. Chapter (4)
Dot (.) and Cross (x) Products The dot or inner product is an operation between two vectors but will result into a scalar: u . v = |u||v|cos( ) i.e., cos( ) = u . v / |u||v|. u . u = |u| 2 From this, one find that u and v are orthogonal. The cross product is an operation between two vectors and will result into a vector: u v = |u||v|sin( ) i.e., sin( ) = u v / |u||v|. u u = 0 thump u v u v Right-hand rule Chapter (4)
Planes A plane in an affine space and can be defined as a direct extension of the parametric line. From geometry, any three points that are not on one line will make a unique plane. Let’s do some math here. We want to prove that we need a point and two vectors to make a plane. Chapter (4)
Three-Dimensional Primitives • In the 3-D space, there are many varieties for geometric objects. • There are two problems when we expand our graphics system to incorporate all the possibilities: • First, the mathematical definition of 3-d objects may be very complex, • Second, we are interested in only those objects that lead to efficient implementations in graphics systems. • Three features characterized 3-D objects: • The objects are described by their surfaces and can be thought of as being hallow, • The objects can be specified through a set of vertices in 3-D, and • The objects either are composed of or can be approximated by flat convex polygons. Curves in 3-D Surfaces in 3-D Volumes in 3-D Chapter (4)
Coordinate Systems and Frames In the 3-D space, any vector w can be represented uniquely in terms of any three linearly independent vectors, v1, v2, and v3. This can be written in matrix form: The T in aT, denotes the transpose of a. A good example for v1, v2, and v3 can be the Cartesian axes, x, y, and z. Chapter (4)
Coordinate Systems and Frames – cont. Sometimes, all the vectors are not coming from the same reference point. Within a frame, we still have: But for every point we need to know where the origin is located, and should consider that. Where P0 is the origin of the vector coordinate system. Thus, the representation of a particular vector in a frame requires three scalars. The representation of a point requires three scalars and the knowledge of where the origin is located. Chapter (4)
Change of Coordinate Systems Often, we are required to represent a vector when we change the basis vectors. Suppose we have {v1, v2, v3} and {u1, u2, u3} as the two bases. Each basis vector in the second set can be represented in terms of the first basis (and vice versa). Where a scalar components will make a 3x3 matrix: M contains all the information to go from one representation of a vector in one basis to its representation in the second basis. The inverse of M, i.e., M-1 will tell us how to go from {u1, u2, u3} to {v1, v2, v3}. Chapter (4)
Change of Coordinate Systems – cont. Suppose a vector w with with respect to {v1, v2, v3}; Assume also that representation of w with respect to {u1, u2, u3} is: We know that: We can write, w in terms of these two: w = bTu = bTMv = aT v Thus, a = MTb and b = Aa = (MT)-1a An Example. Chapter (4)
Example Suppose we have, , and we want to make a new basis from the three vectors v1, v2, and v3. w = ? ( note: = )= u1 = v1 u2 = v1 + v2 u3 = v1 + v2 + v3 M = A = (MT)-1 = b = Aa w = Chapter (4)
Example Suppose we have, , and we want to make a new basis from the three vectors v1, v2, and v3. w = ? ( note: = )= u1 = v1 u2 = v1 + v2 u3 = v1 + v2 + v3 A = b = w = -1u1 – 1u2 + 3u3 b u Chapter (4)
Homogeneous Coordinates Usually, we represent a point P located at (x, y, z) using a 3-D frame determined by P0, v1, v2, and v3with a column matrix: Where, x, y, and z are the components of the basis vectors for this point, so that We can represent a point the same way: So w can be shown as: There are some problems with this procedure: 1) we prefer to distinct points from vectors 2) without distinction between the two, implementation would be very hard. Chapter (4)
Homogeneous Coordinates What is the difference between the vector that is drawn from {1,1,1} to {2,3,4} and the one that is drawn between {0,0,0} and {1,2,3}? We wish to maintain points and vectors as distinct geometric types. We use homogeneous coordinates to avid the problem. We agree that a point be presented as: where P0 = 0 or P0 = 1. We can write this as: The 4-D matrix on the right side of this equation is called the homogenous-coordinate representation. In this frame, any vectorw can be written as: Thus w can be represented by a column matrix as: Chapter (4)
Homogeneous Coordinates – Change of frames Change of frames using the homogeneous coordinates becomes much simpler. Suppose we have the two frames (v1, v2, v3, P0) and (u1, u2, u3, Q0) and we want to express the basis vectors and reference point of the second frame in terms of the first as: These equations can be written in matrix form as: where M is the 4x4 matrix defined as: M is called the matrix representation of the change of frames. We can use M to compute the changes in the representations either of two points or of two vectors in the two frames. How? Chapter (4)
Example Suppose we have, , and we want to make a new basis from the three vectors v1, v2, and v3. u1 = v1 u2 = v1 + v2 u3 = v1 + v2 + v3 Let’s compute a and b. Suppose we have Q0 = P0 + v1 + 2v2 + 3v3 M = MT = A = (MT)-1 P = P’ = Aa vector a = b = Aa = Chapter (4)
Example Suppose we have, , and we want to make a new basis from the three vectors v1, v2, and v3. u1 = v1 u2 = v1 + v2 u3 = v1 + v2 + v3 Point: Q0 = v1 + 2v2 + 3v3 + P0 point a vector a Chapter (4)
Frames and ADTs So far we have learned to define some primitive objects such as points, lines, and planes. We want to write computer code such as: point3 p,q; or vector3 v,u; Then, we want to write programs in terms of these types. In C++ that supports overloading we can write the operators as: q = q+v; or u = p – q; But we cannot write: q = v; or u = p + q; In C, we can define the point3 data type as: typedef float point3[4]; Then a homogeneous coordinate representation can be written: typedef float point2[4]; In C we use something like; point3 p = {1.0, 2.0, 3.0}; There are two problems with this: 1) we have mixed the implementation with the data type, and 2) we cannot determine the coordinate system that is used. How do we solve these problems? Chapter (4)
Frames in OpenGL The are two frames in OpenGL, 1) the camera frame, and 2) the world frame. The model-view matrix positions the world frame relative to the camera frame. Thus, the model-view matrix converts the homogeneous-coordinate representations of points and vectors to their representations in the camera frame. There are three basic vectors: 1) up direction of the camera, y direction 2) the direction where camera is pointing, negative z direction 3) the direction to make the x, y, and z right-handed coordinate, x. Chapter (4)
Frames in OpenGL-cont. If we regard the camera frame as fixed and the model-view matrix as positioning the world frame relative to the camera frame, then the model-view matrix, Moves a point (x,y,z) in the world frame to the point (x,y,z, -d) in the camera frame. By making d a suitably large positive number, we “move” the objects in front of the camera by moving the world frame relative to the camera frame. Chapter (4)
Modeling a Colored Cube • Modeling • Converting to the camera frame • Clipping • Projecting • Removing hidden surface • Rasterizing • GLfloat vertices[8][3] = {{-1.0,-1.0,-1.0}, {1.0,-1.0,-1.0}, {1.0,1.0,-1.0}, • {-1.0,1.0,-1.0}, {-1.0,-1.0,1.0}, {1.0,-1.0,1.0}, {1.0,1.0,1.0}, {-1.0,1.0,1.0}}; • If we use a more object-oriented approach: typedef GLfloat point3[3]; • point3 vertices[8] = {{-1.0,-1.0,-1.0}, {1.0,-1.0,-1.0}, {1.0,1.0,-1.0}, • {-1.0,1.0,-1.0}, {-1.0,-1.0,1.0}, {1.0,-1.0,1.0}, {1.0,1.0,1.0}, {-1.0,1.0,1.0}}; • OpenGL implements all vertices in 4-D homogeneous coordinates. Function calls such glVertex3fv, have the values placed into 4 dimensional form within the graphics system. Chapter (4)
Modeling a Colored Cube – cont. We can use the list of points to define the faces of the cube. One of the faces is: glBegin(GL_POLYGON); glColor3fv(vertices[0]); glNormal3fv(vertices[3]); glVertex3fv (vertices[2]); glColor3fv (vertices[1]); glEnd(); Note that the face is outward when the vertices are Inward-and Outward-Pointing Faces are met in a counterclockwise order. Chapter (4)
Modeling a Colored Cube – cont. • We can use the vertex list to define a color cube: typdef GLfloat point3[3]; • point3 vertices[8] = {{-1.0,-1.0,-1.0}, {1.0,-1.0,-1.0}, {1.0,1.0,-1.0}, • {-1.0,1.0,-1.0}, {-1.0,-1.0,1.0}, {1.0,-1.0,1.0}, {1.0,1.0,1.0}, {-1.0,1.0,1.0}}; • GLfloat colors[8][3] = {{0.0,0.0,0.0}, {1.0,0.0,0.0}, {1.0,1.0,0.0}, • {0.0,1.0,0.0}, {0.0,0.0,1.0}, {1.0,0.0,1.0}, {1.0,1.0,1.0}, {0.0,1.0,1.0}}; • void quad(int a, int b, int c, int d) • { • glBegin(GL_QUADS); • glColor3fv(colors[a]); • glVertex3fv(vertices[a]); • glColors3fv(colors[b]); • glVertex3fv(vertices[b]); • glColor3fv(colors[c]); • glVertex3fv(vertices[c]); • glColors3fv(colors[d]); • glVertex3fv(vertices[d]); • glEnd(); • } void colorcube() { quad(0,3,2,1); quad(2,3,7,6); quad(0,4,7,3); quad(1,2,6,5); quad(4,5,6,7); quad(0,1,5,4); } Chapter (4)
Bilinear Interpolation We can define the color of each vertex in the cube, but how do we color the faces, i.e., color the points inside the polygon. Let’s start with a simple example to understand the interpolation. Suppose the value of y at x=100 is 600 and its value at x = 500 is 100. How can we find y at x = 150 and x = 200 and x = 250 using the given data at x = 100 and x = 500. The process can be formulated as: Can you expand this definition to a more Complicated case like the one given in this Figure? 600 100 100 200 500 Chapter (4)
Example Suppose the following two vertices are given with two distinct colors. What is the color of the vertices at Midway between the two vertices? Quarter distance from the red vertex? Quarter distance from the blue vertex? Blue (0,0,1) Red (1,0,0) Chapter (4)
Example Suppose the following three vertices are on an isosceles triangle. What is the color at the center of the triangle? Blue (0,0,1) Red (1,0,0) Red (1,0,0) Chapter (4)
Scan-line Interpolation – cont. This method works fine for a flat quadrilateral. Each color generated by this method corresponds to a point on the polygon. If the four vertices are not in the same plane, then, although a color is generated, its location on a surface is not clearly defined. A new method can be used for this purpose. In this case, a polygon is filled only when it is displayed. If we wait until rasterization, the polygon is first projected onto the 2-D plane. We can use this to fill a quadrilateral scan line by scan line. Then colors are assigned scan line by scan line on the basis of only two edges. OpenGL provides this method for colors as well as for other values. Scan-line interpolation Projection of a plane Chapter (4)
Vertex Arrays We used vertex lists to model the cube. When we draw the cube this way, we are making many calls to OpenGL functions. If we assign a color to each vertex, we make 50 OpenGL calls: 6 faces (each with glBegin and glEnd), 4 to glColor, and 4 to glVertex. Vertex arrays provide a method for encapsulating the information in our data structure such that we can draw polydehral objects with only a few function calls. There are three steps in using vertex arrays: 1) we enable the functionality of vertex arrays, 2) we tell OpenGL, where and in what format the arrays are, and 3) we render the object. OpenGL allows 6 different types of arrays (vertex, color, color index, normal, texture coordinate, and edge flag). The items can be place in between the glBegin and glEnd. For the rotating cube, we need only colors and vertices. We enable these two by: glEnableClientState(GL_COLOR_ARRAY); glEnableClientState(GL_VERTEX_ARRAY); Chapter (4)
Vertex Arrays – cont. • The arrays are the same as before: • GLfloat vertices[] = {{-1.0,-1.0,-1.0}, {1.0,-1.0,-1.0}, {1.0,1.0,-1.0}, • {-1.0,1.0,-1.0}, {-1.0,-1.0,1.0}, {1.0,-1.0,1.0}, {1.0,1.0,1.0}, {-1.0,1.0,1.0}}; • GLfloat colors[] = {{0.0,0.0,0.0}, {1.0,0.0,0.0}, {1.0,1.0,0.0}, • {0.0,1.0,0.0}, {0.0,0.0,1.0}, {1.0,0.0,1.0}, {1.0,1.0,1.0}, {0.0,1.0,1.0}}; • We next identify where the arrays are: • glVertexPointer(3, GL_FLOAT, 0, vertices); //The first three are: 3-D colors and vertices • glColorPointer(3, GL_FLOAT, 0, colors); //stored as floats and elements are contiguous // in the arrays. • The fourth argument is a pointer to the actual array. • What is the relationship between the vertices and the faces of the cube? • GLubyte cubeIndices[24] = [0, 3, 2, 1, 2, 3, 7, 6, 0, 4, 7, 3, 1, 2 ,6, 5, 4, 5, 6, 7, 0, 1, 5, 4}; • The next thing is to render the cube. Chapter (4)
Vertex Arrays – cont. We have few options regarding how to draw the arrays: glDrawElements(type, n, format, pointer); Here type is the type of elements, such as line or polygon, that the arrays define. n is the number of elements that we wish to draw, format describes the form of the data in the index array, and pointer points to the first index to use. For our cube we can make six calls: for(I = 0; I < 6; I++) glDrawElements(GL_POLYGON, 4, GL_UNSIGNED_BYTE, &cubeIndices[4*I]); Thus, once we set up and initialized the arrays, to draw the cube, we have only 6 function calls. Even better, we can draw with one call: glDrawElements(GL_QUADS, 24, GL_UNSIGNED_BYTE, cubeIndices); Chapter (4)
Affine Transformations A transformation is a function that takes a point (or vector) and maps that point (or vector) into another point (or vector). For a point: Q = T(P) and for a vector: v = R(u) In a homogeneous coordinate, we can represent both vectors and points as four-dimensional column matrices and can define the transformation with a single function: q = f(p) andv = f(u). This transforms the representations of both points and vectors in a given frame. Problems: This formulation is very general to be useful In an affine space, any vector is represented as: Any point, p, can be written as: If we apply an arbitrary A to a vector, v = Au, only 9 of the elements of A affect u (9 degrees of freedom in the transformation matrix). On the other hand, the affine transformation of points have the full 12 degrees of freedom. For a line , where P0is a point and d is a vector. In any frame, the line can be expressed as: , where p0 and d are the representations of P0and d in the frame. How about transformation of the line by a transformation matrix A? Chapter (4)
Rotation, Translation, and Scaling Translation is an operation that displaces points by fixed distance in a given direction. To specify a transformation, we need only to specify a displacement vector d, because the transformed points are given by P’ = P + d. Translation has 3 degrees of freedom, why? Chapter (4)
Rotation, Translation, and Scaling Rotation is more difficult to specify than translation, because more parameters are involved. Simple example: Rotate a point (x,y) about its origin by u. x = r cos(f), y = r sin(f) x’ = r cos(u + f) y’ = r sin(u + f) cos(u + f) = cos(u) cos(f) - sin(u) sin(f) AND sin(u+f) = sin(u) cos(f) + cos(u) sin(f) x’ = r cos(f) cos(u) – r sin(f) sin(u) = x cos(u) – y sin(u) y’ = r cos(f) sin (u) + r sin(f) cos(u) = x sin(u) + y cos(u) In matrix form: Note three things: 1) rotation is around a fixed point, 2) A positive rotation in x-y plane is the rotation counterclockwise around z. 3) 2-D rotation is 3-D rotation around z. (x’,y’) Chapter (4)
Rotation, Translation, and Scaling A general 3-D rotation that is independent of the frame can be formalized when the following three entities are defined: 1) A fixed point (Pf) 2) A rotation angle 3) A line or vector about which to rotate. The 3 degrees of freedom are: The two angles necessary to specify the orientation of vector and the angle that specifies the amount of rotation about the vector. Note: no combination of rotation and translation can alter the shape of the object. They can alter the object location and orientation. Chapter (4)
Rotation, Translation, and Scaling Scaling is an affine non-rigid body transformation. We can combine a properly chosen sequence of scalings, translations, and rotations to form any affine transformation. Chapter (4)
Translation in Homogeneous Coordinates Within a frame, each affine transformation is represented by a 4x4 matrix of the form: A point p will be moved to point p’ by a displacement distance d: p’ = p + d. The translation matrix is defined as T (dx ,dy,, dz): The inverse of a translation matrix is obtained by applying an inversion algorithm or by noting that, if we displace a vector by d we can return it to its original position by Displacing it by –d: T-1(dx, dy, dz)= T(-dx ,-dy,, -dz) Chapter (4)
Scaling in Homogeneous Coordinates For both scaling and rotation, there is a fixed point that is unchanged by the transformation. These three can be combined as: p’ = Sp The inverse of scaling matrix is: Chapter (4)
Rotation in Homogeneous Coordinates We can have rotation around three axes, As an example rotation around z axis is: This can be written I matrix form as: P’ = Rzp where Rzis defined as: Rotation around z axis: Rotation around x axis: The rotation can be reversed for all of them using the following procedure: Chapter (4)
Shear in Homogeneous Coordinates We can construct any affine transformation from a sequence of rotations, translations, and scalings. Since shear is very important, we rather define it directly. Shear in x direction (x’, y’) The inverse can be computed as: Chapter (4)
OpenGL Transformation Matrices In OpenGL, there are three matrices that are part of the state. We will use the model-view matrix in this chapter. All three types are manipulated by a common set of functions, and we use the glMatrixMode function to select the matrix to which the operations apply. The generalization common to most graphics systems is the current transformation matrix (CTM). Suppose C denotes the CTM. C I (initialize C to unit matrix) The functions that alter C are of two forms: 1) Those that reset it to some matrix 2) Those that modify it by pre-multiplication or post-multiplication by a matrix. Three transformation are supported by most systems: translation, scaling with a fix point at the origin, and rotation with a fixed point of the origin. These can be written as: C CT C CS C CR With an arbitrary matrix, M, this can be written as: C CM. Chapter (4)
Rotation, Translation, and Scaling in OpenGL The OpenGL functions for these transformations are (e.g.) void glRotatef(GLfloat angle, GLfloat x, GLfloat y, GLfloat z) angle :Specifies the angle of rotation, in degrees. x, y, z : Specify the x, y, and z coordinates of a vector, respectively. glRotate computes a matrix that performs a counterclockwise rotation of angle degrees about the vector from the origin through the point (x, y, z). Example: to rotate 30 degrees around the y-axis we could call glRotatef(30,0,1,0); void glScalef(GLfloat x, GLfloat y, GLfloat z) x, y, z: Specify scale factors along the x, y, and z axes, respectively. glScale produces a general scaling along the x, y, and z axes. The three arguments indicate the desired scale factors along each of the three axes. Chapter (4)
Rotation, Translation, and Scaling in OpenGL void glTranslatef(GLfloat x, GLfloat y, GLfloat z) x, y, z : Specify the x, y, and z coordinates of a translation vector. glTranslate moves the coordinate system origin to the point specified by (x, y, z). Example (A simple cube): typedef GLfloat point3[3]; point3 p[8]={ {0,0,0}, //black {0,0,1}, //blue {1,0,1}, //magenta {1,0,0}, //red {0,1,0}, //green {0,1,1}, //green+blue {1,1,1}, //white {1,1,0} //yellow }; Chapter (4)
void drawPoint(int i){ glVertex3fv(p[i]); } void drawFace(int i1,int i2,int i3,int i4){ glBegin(GL_POLYGON); glColor3fv(p[i1]); drawPoint(i1); drawPoint(i2); drawPoint(i3); drawPoint(i4); glEnd(); } Our display function will include the code: drawFace(0,3,2,1); //bottom = black, drawFace(1,2,6,5); //front = blue drawFace(2,3,7,6); //right side = magenta drawFace(3,0,4,7); //back side = red drawFace(4,5,6,7); //top = white drawFace(5,4,0,1); //left side = yellow Chapter (4)
The complete program for the simple cube #include <stdlib.h>#include <GL/glut.h> static GLint axis = 2; const pi = 3.14159; static GLfloat theta= pi * 90/180; typedef GLfloat point3[3]; point3 p[8]={ {0,0,0}, //black {0,0,1}, //blue {1,0,1}, //magenta {1,0,0}, //red {0,1,0}, //green {0,1,1}, //green+blue {1,1,1}, //white {1,1,0} //yellow }; void drawPoint(int i){ glVertex3fv(p[i]); } void drawFace(int i1,int i2,int i3,int i4){ glBegin(GL_POLYGON); glColor3fv(p[i1]); drawPoint(i1); drawPoint(i2); drawPoint(i3); drawPoint(i4); glEnd(); } Chapter (4)
The complete program for the simple cube – cont. void display(void) {/* display callback, clear frame buffer and z buffer, rotate cube, draw, swap buffers*/ glClear(GL_COLOR_BUFFER_BIT); glLoadIdentity(); drawFace(0,3,2,1); //bottom = black, drawFace(1,2,6,5); //front = blue drawFace(2,3,7,6); //right side = magenta drawFace(3,0,4,7); //back side = red drawFace(4,5,6,7); //top = white drawFace(5,4,0,1); //left side = yellow glFlush(); } Chapter (4)
The main function for the simple cube void main(int argc, char **argv) { glutInit(&argc, argv); glutInitDisplayMode (GLUT_SINGLE | GLUT_RGB); /* default, not needed */ glutInitWindowSize(500, 500); glutCreateWindow("colorcube"); glutDisplayFunc(display); glutMainLoop(); } Chapter (4)
The Cube example with spinning and more … #include <stdlib.h> #include <GL/glut.h> GLfloat vertices[][3] = {{-1.0,-1.0,-1.0},{1.0,-1.0,-1.0}, {1.0,1.0,-1.0}, {-1.0,1.0,-1.0}, {-1.0,-1.0,1.0}, {1.0,-1.0,1.0}, {1.0,1.0,1.0}, {-1.0,1.0,1.0}}; GLfloat normals[][3] = {{-1.0,-1.0,-1.0},{1.0,-1.0,-1.0}, {1.0,1.0,-1.0}, {-1.0,1.0,-1.0}, {-1.0,-1.0,1.0}, {1.0,-1.0,1.0}, {1.0,1.0,1.0}, {-1.0,1.0,1.0}}; GLfloat colors[][3] = {{0.0,0.0,0.0},{1.0,0.0,0.0}, {1.0,1.0,0.0}, {0.0,1.0,0.0}, {0.0,0.0,1.0}, {1.0,0.0,1.0}, {1.0,1.0,1.0}, {0.0,1.0,1.0}}; Chapter (4)