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.
// 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); }
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