Hon Yu's Home Page

****** Outline *******

  This class allows 3-D drawing of crystal structure to be
written as a postscript file, which is device-independent
and this in turn could be displayed on the computer screen or
printed out on a postscript-printer.  It will allow user to
choose things like lattice-type & basis which would then be
put together to draw up the crystal and also once drawn user
could rotate it into any orientation he or she wants to see it.

Comments:

                          
// My 3 classes (Crystal, Lattice, Basis) along with Point/Array classes
   compile now(finally) and can be run now with main.c.  I've decided
   to use after all(after some struggle) 2-D Array class to store
   the coordinates of the points (instead of array of point class).
   The needed files are following: Array.h/.c Point.h/.c
   (both of which were modified a bit for this) header.h
   functions.c and main.c which are all located under hjyu/WWW folder
   in my sun account(along with all the *.o files and the executable
   file called run.demo and the postscript file named out.ps).  
   I would suggest copying/downloading these files from my folder/sub-
   directory if you want to test it out....(sorry for any inconvenience
   for this...I simply didn't have time to work on my web-page at all
   this time around)

// There seemed to be some problem with 'segmentation fault' while 
   I was testing my program...which now mysteriously has gone and I 
   can't seem to duplicate that any more.

// Here are some basic run-down on how my program could be run...

   Compile: sun1%g++ -o run.demo Array.o Point.o functions.o main.o

   You have to enter the data of lattice and basis from the keyboard
   (unforturnately for now) after you type in the executable file 'run.demo',
   and here is an example of one(say, 2-D simple-cube with one atom basis)
         Enter Dimensionality of lattice....
            2
         Enter translational lattice vectors....
            1.0 0.0
            0.0 1.0
         Enter the initial integers for the lattice vectors...
            0 0
         Enter the max. crystal length to be drawn...
            1.43                                      => sqrt(2.0)
         Enter Dimensionality of basis...
            2
         Enter # of basis atoms
            1
         Enter the positions of basis atoms(x, y/ x, y, z)..
            0.0 0.0
         Enter the viewing angles r.s.t. Z & Y axis...
            0.0 0.0

// To be honest I haven't done all things that I've initially wanted
   on my project...for an instance, entering the dimen. of basis came from
   my initial plan to have 2 input files for data of lattice and basis
   so once you've created an input for a basis you could use it for
   other type of lattice and so on.  But as it stands now my project
   at least can deal with 2 or 3-D crystal of any lattice type with
   no limit on the number of basis atoms.
   *** BTW, the translational lattice vectors above should be in terms
       of unit vectors(that is, in FCC case they should be 0.5 0.5 0.0,
       0.5 0.0 0.5, 0.0 0.5 0.5) and the initial integers for them are
       needed to generate the lattice-points/basis-positions and also
       to know whether the origin is at the corner of cube(FCC...etc.)
       or some arbitrary location in the crystal.  And the max. length
       of crystal is needed to limit the size of the crystal to be
       drawn(for example, for 3-D simple cube case if you want to draw
       only one cube(unit cell) this should be sqrt(3.0)=1.73 which
       is the distance between the two opposite corners and if you
       want 8 cubes you should enter 2 times of that, 2*1.73 and so on).
   *** The viewing angles represent the angles at which you want to 
       observe the crystal on the screen/page; it's positive turning
       clockwise looking down on the respective axis(Z or Y but not
       on X because you are looking down along X-axis with those two angles
       equal to zero and there is no point rotating around X-axis!)

// Once run the program creates a postscript file named 'out.ps' which
   could be viewed with 'gs' command in unix(need a xterm terminal 
   setting first); simple type in command 'gs'(ghost script) on it.

   gs out.ps


// BTW, I've decided not to draw the lattice....because I couldn't come
   up any reasonable logic to decide which lattice pts are to be 
   connected with which.  (For example, if you have a FCC lattice
   the question becomes Do you connect all the pts. with each other,
   the pt. on the face with the ones on the corners... or the ones on
   the opposite face??)  The compromise was to simply locate all the 
   basis atoms in the defined size of crystal and draw a circle with 
   varying gray-scale for each type of atom(but, the size of circle
   was fixed: defined in header.h).

// ***Features to be added (hopefully...)
   1. ability to choose a plane to view in 3-D crystal 
   2. use of a file to read in all the parameters to draw a crystal

// *** The sub-directory path to the all the related files to this is
      (in the Sparc-stations/sun1,2,3,4,5 account):

      hjyu/WWW




// header.h

#include 
#include 
#include 
#include 
#include 
#include "Array.h"
#include "Point.h"

#define LATTICE_PT_SIZE 100
#define BASIS_PT_SIZE 150
#define PS_LATTICE_PT_SIZE 100
#define PS_BASIS_PT_SIZE 150
#define PS_ATOM_SIZE 25.0
#define MAX_SCREEN 370.0
#define SHIFT_ORIGIN 70.0
     

class Lattice
{
   public:
     Lattice();
     friend istream& operator>>(istream&, Lattice&);
     friend class Crystal;

   private:
     Array2 trans_vect;
     int crystal_Dim;
     int* init_int;
     float max_length_crystal;
};


class Basis
{
   public:
     Basis();
     friend istream& operator>>(istream&, Basis&);
     friend class Crystal;

   private:
     Array2 basis_posit;
     int num_of_basis, basis_Dim;
};


class Crystal
{
   public:
     Crystal();
     void make_crystal(const Lattice&, const Basis&, float z, float y);
     void file_out(const Crystal&);  //Postscript-file out!
//     friend ofstream& operator<<(ofstream&, Crystal&);  //Postscript-File Out!

   private:
     int* tot_count;
     int tot_num_basis;
     int tot_num_lattice;
     int num_basis;
     Array2 lattice_pt;
     Array2 basis_pt;
     Array2 post_lattice_pt;
     Array2 post_basis_pt;
}; 



// functions.c

#include "header.h"
extern float abs(float);

Lattice::Lattice() {}

istream& operator>>(istream& instream, Lattice& l)
{
   int n;
   cout << "Enter Crystal-Dimensionality (2 or 3): " << endl;
   instream >> n;
   l.crystal_Dim = n;
   l.trans_vect.setSize(n, n);

   cout << "Enter translational lattice unit-vectors(x,y or x,y,z): " << endl;
   for (int i = 0; i < n; i++)
   {
      for (int j = 0; j < n; j++) instream >> l.trans_vect(i, j);
   }

   l.init_int = new int[n];
   cout << "Enter min. integers for the unit-vectors: " << endl;
   for (int k = 0; k < n; k++) instream >> l.init_int[k];

   cout << "Enter the max. length of the crystal to be drawn: " << endl;
   float m;
   instream >> m;
   l.max_length_crystal = m;
   
   return instream;
}


Basis::Basis() { }

istream& operator>>(istream& instream, Basis& b)
{
   int m, n;
   cout << "Enter the dimensionality (2 or 3) of basis: " << endl;
   instream >> n;

   cout << "Enter the # of basis atoms: " << endl;
   instream >> m;
   b.basis_Dim = n;
   b.num_of_basis = m;
   b.basis_posit.setSize(m, n);

   cout << "Enter the positions of the basis atoms(x,y or x,y,z r.s.t.origin):"
        << endl; 
   for (int i = 0; i < m; i++)
   {
      for (int j = 0; j < n; j++) instream >> b.basis_posit(i, j);
   }
   
   return instream;
}

Crystal::Crystal() { }

void Crystal::make_crystal(const Lattice& l, const Basis& b, float z, float y)
{
   if (l.crystal_Dim != b.basis_Dim)
   {
     cout << "Incomparitable Dimensionality-Match between Lattice & Basis!";
     cout << endl;
     exit(0);
   }   
     tot_count = new int[b.num_of_basis]; 
     post_lattice_pt.setSize(PS_LATTICE_PT_SIZE, 2);    //These store the x&y
     post_basis_pt.setSize(PS_BASIS_PT_SIZE, 2);   //postscript coords.  

   if (l.crystal_Dim == 2)  {     //Construct 2-D Crystal
     Point origin, t;
     int counter1 = 0;

//Following 'for' loops construct postscript x&y coords. of lattice points
//according to the max. crystal length supplied by the user.

     for (int i=l.init_int[0]; sqrt(pow(i*l.trans_vect(0,0), 2)+
          pow(i*l.trans_vect(0,1),2)) <= l.max_length_crystal; i++)
     {
        for (int j=l.init_int[1]; sqrt(pow(j*l.trans_vect(1,0),2)+
             pow(j*l.trans_vect(1,1),2)) <= l.max_length_crystal; j++)
        {
           t.moveTo(i*l.trans_vect(0,0)+j*l.trans_vect(1,0),
                    i*l.trans_vect(0,1)+j*l.trans_vect(1,1), 0.0);
           if (origin.distance(t) <= l.max_length_crystal)
           {
        post_lattice_pt(counter1,0) = i*l.trans_vect(0,0)+j*l.trans_vect(1,0);
        post_lattice_pt(counter1,1) = i*l.trans_vect(0,1)+j*l.trans_vect(1,1);
        counter1++;
           }
           t=(0.0);
        }
        t=(0.0);
     }
     tot_num_lattice = counter1;

//Following 'for' loops construct postscript x&y coords. of basis positions
//according to the max. crystal length supplied by the user.
     Point atom;
     int count = 0;
     for (int ib=0; ib= maxX) maxX = c.post_basis_pt(k,0); 
   for (int j1=0; j1 < c.tot_num_basis; j1++)  
       if (c.post_basis_pt(j1,1) <= minY) minY = c.post_basis_pt(j1,1); 
   for (int k1=0; k1 < c.tot_num_basis; k1++)  
       if (c.post_basis_pt(k1,1) >= maxY) maxY = c.post_basis_pt(k1,1); 
                    
   float scale_fac;
   if (abs(maxX-minX) < abs(maxY-minY)) { scale_fac = abs(maxY-minY); }
   else { scale_fac = abs(maxX-minX); }
   float fudge_fac = MAX_SCREEN/scale_fac;
   float origin_pos = fudge_fac/2.0 - SHIFT_ORIGIN;
//-------------------------------------------------------------------------//

   FILE* fp;
   fp = fopen("out.ps", "w");
   fprintf(fp,"%%This is a postscript file drawing a 2 or 3-D Crystal%%\n");
   fprintf(fp,"%\n");
   fprintf(fp,"/NewOriginX %f def\n", origin_pos);
   fprintf(fp,"/NewOriginY %f def\n", origin_pos);
   fprintf(fp,"/RadiusAtom %f def\n", PS_ATOM_SIZE);
   fprintf(fp,"%%\n");
   fprintf(fp,"newpath\n");
   fprintf(fp,"NewOriginX NewOriginY translate\n");
   fprintf(fp,"%%\n");

   float x, y;
   int skip = 0;
   for (int m=0; m < c.num_basis; m++) 
   {     fprintf(fp,"%f setgray\n", gray_scale[m]);  
    for (int m1=0; m1 < c.tot_count[m]; m1++)  {
         x = fudge_fac*c.post_basis_pt(m1+skip,0);
         y = fudge_fac*c.post_basis_pt(m1+skip,1);
    fprintf(fp,"%f %f RadiusAtom 0 360 arc fill\n", x, y);  }
    skip += tot_count[m];
   }
   fprintf(fp,"showpage\n");
   fclose(fp);
}

// main.c
#include "header.h"

void main() {

 Lattice a;
 cin >> a;

 Basis b;
 cin >> b;

 float theta_z, theta_y;
 cout << "Enter Viewing Angles(Degree) r.s.t. Z & Y axis(c.c.= -ang.)" << endl;
 cout << "(These angles have no effect on 2-D crystal!)" << endl;
 cin >> theta_z >> theta_y;

 Crystal c;
 c.make_crystal(a, b, theta_z, theta_y);
 c.file_out(c);
}
                    

Sample Postscript file:


newpath    %Try a = 220 (3 inches)
%
%Define a circle to be drawn
%
%/doACircle
%{}
%
300 300 translate
0 0 moveto	%origin
0 206.8 lineto	%(001)
	%[4 2] 0 setdash 
169.4 206.8 lineto %(011)	
	%[] 0 setdash 
28.6 132 lineto	%(111) 
-140.8 132 lineto %(101)
0 206.8 lineto
-140.8 132 moveto
-140.8 -74.8 lineto 	%(100)
0 0 lineto 
0 0 moveto		%(000)
169.4 0 lineto
169.4 206.8 lineto
169.4 0 moveto		%(010)
	%[4 2] 0 0 setdash 
28.6 -74.8 lineto 	%(110)
28.6 132 lineto
28.6 -74.8 moveto
	%[] 0 setdash 
-140.8 -74.8 lineto	%(100)
stroke
%
%Draw a filled circle(radius=50*1/72 inch.) on each corner
%
newpath
%300 300 translate
0 0 20 0 360 arc
fill
0 206.8 20 0 360 arc
fill
169.4 206.8 20 0 360 arc
fill
28.6 132 20 0 360 arc
fill
-140.8 132 20 0 360 arc
fill
-140.8 -74.8 20 0 360 arc
fill
28.6 -74.8 20 0 360 arc
fill
169.4 0 20 0 360 arc
fill
showpage