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