FOX/ObjCryst++  2022
wxCrystal.cpp
1 /* ObjCryst++ Object-Oriented Crystallographic Library
2  (c) 2000-2009 Vincent Favre-Nicolin vincefn@users.sourceforge.net
3  2000-2001 University of Geneva (Switzerland)
4 
5  This program is free software; you can redistribute it and/or modify
6  it under the terms of the GNU General Public License as published by
7  the Free Software Foundation; either version 2 of the License, or
8  (at your option) any later version.
9 
10  This program is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  GNU General Public License for more details.
14 
15  You should have received a copy of the GNU General Public License
16  along with this program; if not, write to the Free Software
17  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 */
19 #include <sstream> //for stringstream
20 #include <fstream>
21 
22 #include <stdlib.h>
23 
24 // wx headers, with or without precompilation
25 #include "wx/wxprec.h"
26 #ifdef __BORLANDC__
27  #pragma hdrstop
28 #endif
29 #ifndef WX_PRECOMP
30  #include "wx/wx.h"
31 #endif
32 #include "wx/notebook.h"
33 #include "wx/minifram.h"
34 
35 #include "ObjCryst/wxCryst/wxCrystal.h"
36 
37 #include "wx/colordlg.h"
38 #include "wx/progdlg.h"
39 #include "wx/busyinfo.h"
40 #include "wx/config.h"
41 
42 #include "ObjCryst/Quirks/Chronometer.h"
43 #include "ObjCryst/ObjCryst/Atom.h"
44 #include "ObjCryst/ObjCryst/ZScatterer.h"
45 #include "ObjCryst/ObjCryst/Molecule.h"
46 #include "ObjCryst/ObjCryst/PowderPattern.h"
47 #include "ObjCryst/ObjCryst/ScatteringPowerSphere.h"
48 #include "ObjCryst/ObjCryst/Polyhedron.h"
49 
50 #ifdef OBJCRYST_GL
51  #ifdef __WXGTK__
52  #include "GL/glu.h"
53  #endif
54 
55  #ifdef __WXMAC__ // For the wxMac version of wxWindows, i.e. with the "Aqua" look
56  #include <OpenGL/glu.h>
57  #include "AGL/agl.h"
58  #endif
59 
60  #ifdef __LINUX__
61  #include "GL/glx.h"
62  #endif
63 
64  #ifdef __WIN32__
65  #include "gl/glu.h"
66  #endif
67 
68  #ifdef HAVE_GLUT
69  #ifdef __WXMAC__ // For the wxMac version of wxWindows, i.e. with the "Aqua" look
70  #include <GLUT/glut.h>
71  #else
72  #include "GL/glut.h"
73  #endif
74  #endif
75  #ifdef HAVE_FFTW
76  #include "fftw3.h"
77  #endif
78 #endif
79 
80 extern "C" {
81 #include "ObjCryst/wxCryst/trackball.h"
82 }
83 
84 //Fixes for Cygwin; where do those stupid macros come from ? Somewhere in wxMSW headers
85 #ifdef max
86 #undef max
87 #endif
88 #ifdef min
89 #undef min
90 #endif
91 #ifdef DrawText
92 #undef DrawText
93 #endif
94 
95 //#include "ObjCryst/ObjCryst/Map.cpp"
96 
97 namespace ObjCryst
98 {
99 #ifndef HAVE_GLUT
100 // This must be changed for each GL world to the correct first display list,
101 // i.e. in SetCurrent().
102 static int sFontDisplayListBase=0;
103 #endif
104 
105 GLvoid crystGLPrint(const string &s)
106 {
107  glDisable (GL_BLEND);
108  #ifdef HAVE_GLUT
109  for(unsigned int l=0;l<s.size();l++)
110  glutBitmapCharacter(GLUT_BITMAP_HELVETICA_12,*(s.c_str()+l));
111  #else
112  #ifdef __WINDOWS__
113  // Work around a bug in the generic software windows openGL renderer ?
114  // Use a fixed index for the OpenGL display list of characters
115  // See http://stackoverflow.com/questions/10782067/opengl-glcalllists-drawing-incorrect-characters-on-windows-7
116  #if 0
117  static int shift = 0;
118  static bool microsoft_opengl_bug_init = true;
119  if (microsoft_opengl_bug_init)
120  {
121  stringstream sv, sr;
122  sv << glGetString(GL_VENDOR);
123  sr << glGetString(GL_RENDERER);
124  if((sv.str().find("Microsoft Corporation") != std::string::npos) && (sr.str().find("GDI Generic") != std::string::npos))
125  shift = 0;
126  microsoft_opengl_bug_init = false;
127  }
128  #endif
129  for (unsigned int i = 0; i < s.size(); ++i) glCallList(sFontDisplayListBase + (unsigned int)s.c_str()[i]);
130  //VFN_DEBUG_MESSAGE("crystGLPrint():"<<s<<", Vendor:"<<glGetString(GL_VENDOR)<<", Renderer"<<glGetString(GL_RENDERER)<<"(shift="<<shift<<", base="<<sFontDisplayListBase<<")",10)
131  #else
132  glPushAttrib(GL_LIST_BIT);
133  glListBase(sFontDisplayListBase);
134  glCallLists(s.size(), GL_UNSIGNED_BYTE, s.c_str());
135  glPopAttrib();
136  #endif
137  #endif
138  glEnable (GL_BLEND);
139 }
140 
141 // dialog to get a bounding box
142  class UserSelectBoundingBox : public wxDialog {
143  public:
144  UserSelectBoundingBox(wxWindow * parent, const char * title, BBox bbox);
145  ~UserSelectBoundingBox ();
146  BBox GetBBox ();
147  private:
148  void OnOk (wxCommandEvent & WXUNUSED(event));
149  wxTextCtrl * mpXminCtrl, *mpXmaxCtrl;
150  wxTextCtrl * mpYminCtrl, *mpYmaxCtrl;
151  wxTextCtrl * mpZminCtrl, *mpZmaxCtrl;
152  BBox mbbox;
153  DECLARE_EVENT_TABLE()
154  };
155 
156 // dialog to get a triplet of values box
157  class UserXYZBox : public wxDialog {
158  public:
159  UserXYZBox(wxWindow * parent, const wxString &title, Triple xyz);
160  ~UserXYZBox ();
161  Triple GetXYZ ();
162  private:
163  void OnOk (wxCommandEvent & WXUNUSED(event));
164  wxTextCtrl * mpXCtrl;
165  wxTextCtrl * mpYCtrl;
166  wxTextCtrl * mpZCtrl;
167  Triple mXYZ;
168  DECLARE_EVENT_TABLE()
169  };
170 
172 //
173 // WXMolScrolledWindow
174 //
176 WXCrystalScrolledGridWindow::WXCrystalScrolledGridWindow(wxWindow* parent, WXCrystal* p, long id):
177 wxGrid(parent,id),mpWXCrystal(p)
178 {}
179 
180 WXCrystalScrolledGridWindow::~WXCrystalScrolledGridWindow()
181 {
182  if(mpWXCrystal!=0) mpWXCrystal->NotifyDeleteListWin(this);
183 }
184 
186 //
187 // WXCrystal Grid objects
188 //
190 WXCrystal::RowScattPow::RowScattPow():
191 mName("H"),
192 mBiso(1.0),mFormalCharge(0.0),mR(1.0),mG(1.0),mB(1.0),mMaximumLikelihoodError(0.0),mNbGhostAtoms(0.0),
193 mNeedUpdateUI(true),mIdx(-1)
194 {}
195 
197 //
198 // Convert a list of atoms to one molecule
199 //
201 Molecule* Atoms2Molecule(list<Atom *> &vAtom)
202 {
203  VFN_DEBUG_ENTRY("Atoms2Molecule()",6)
204  Molecule *mol=new Molecule((*vAtom.begin())->GetCrystal(),"Molecule");
205  const unsigned long nb=vAtom.size();
206  REAL x0=0,y0=0,z0=0;
207  unsigned int i=0;
208  for(list<Atom *>::iterator pos=vAtom.begin();pos!=vAtom.end();++pos)
209  {
210  REAL x=(*pos)->GetX();
211  REAL y=(*pos)->GetY();
212  REAL z=(*pos)->GetZ();
213  (*pos)->GetCrystal().FractionalToOrthonormalCoords(x,y,z);
214  x0+=x;
215  y0+=y;
216  z0+=z;
217  mol->AddAtom(x,y,z,&((*pos)->GetScatteringPower()),(*pos)->GetName());
218  mol->GetAtom(i++).SetOccupancy((*pos)->GetOccupancy());
219  }
220 
221  CrystVector_REAL x(nb),y(nb),z(nb),radius(nb);
222  vector<pair<const ScatteringPowerAtom *,long> > scattpow(nb);
223  for(unsigned int i=0;i<nb;++i)
224  {
225  x(i)=mol->GetAtom(i).GetX();
226  y(i)=mol->GetAtom(i).GetY();
227  z(i)=mol->GetAtom(i).GetZ();
228  if(mol->GetAtom(i).IsDummy())
229  {
230  radius(i)=-1;
231  scattpow[i].first=0;
232  }
233  else
234  {
235  radius(i)=mol->GetAtom(i).GetScatteringPower().GetRadius();
236  scattpow[i].first=dynamic_cast<const ScatteringPowerAtom *>
237  (&(mol->GetAtom(i).GetScatteringPower()));
238  scattpow[i].second=scattpow[i].first->GetAtomicNumber();
239  }
240  }
241  for(unsigned int i=0;i<nb;++i)
242  {
243  if(scattpow[i].first==0) continue;
244  const REAL x1=x(i),y1=y(i),z1=z(i);
245  x += -x1;
246  y += -y1;
247  z += -z1;
248  for(unsigned int j=i+1;j<nb;++j)
249  {
250  if(scattpow[j].first==0) continue;
251  const REAL dist=sqrt(x(j)*x(j)+y(j)*y(j)+z(j)*z(j));
252  //cout<<" -> d="<<dist<<"("<<radius(i)<<","<<radius(j)<<"):"<<scattpow[i].second<<","<<scattpow[j].second<<endl;
253  if(dist<(1.10*(radius(i)+radius(j))))
254  {
255  if((1!=scattpow[i].second)||(1!=scattpow[j].second))
256  {
257  mol->AddBond(mol->GetAtom(i),mol->GetAtom(j),dist,.01,.02,false);
258  }
259  }
260  }
261  x += x1;
262  y += y1;
263  z += z1;
264  }
265  mol->BuildConnectivityTable();
266  for(map<MolAtom*,set<MolAtom*> >::const_iterator pos=mol->GetConnectivityTable().begin();
267  pos!=mol->GetConnectivityTable().end();++pos)
268  {
269  for(set<MolAtom*>::const_iterator pos1=pos->second.begin();
270  pos1!=pos->second.end();++pos1)
271  {
272  for(set<MolAtom*>::const_iterator pos2=pos1;
273  pos2!=pos->second.end();++pos2)
274  {
275  if(pos2==pos1) continue;
276  if(mol->FindBondAngle(**pos1,*(pos->first),**pos2)== mol->GetBondAngleList().end())
277  mol->AddBondAngle(**pos1,*(pos->first),**pos2,
278  GetBondAngle(**pos1,*(pos->first),**pos2),0.01,0.02,false);
279  }
280  }
281  }
282  x0 /= nb;
283  y0 /= nb;
284  z0 /= nb;
285  mol->GetCrystal().OrthonormalToFractionalCoords(x0,y0,z0);
286  mol->SetX(x0);
287  mol->SetY(y0);
288  mol->SetZ(z0);
289  mol->UpdateDisplay();
290  VFN_DEBUG_EXIT("ZScatterer2Molecule()",6)
291  return mol;
292 }
293 
295 //
296 // WXCrystal
297 //
299 static const long ID_CRYSTAL_MENU_SAVECIF =WXCRYST_ID();
300 static const long ID_CRYSTAL_MENU_SAVETEXT =WXCRYST_ID();
301 static const long ID_CRYSTAL_MENU_DISPLAY =WXCRYST_ID();
302 static const long ID_CRYSTAL_MENU_DISPLAY_3DVIEW =WXCRYST_ID();
303 static const long ID_CRYSTAL_MENU_SCATT =WXCRYST_ID();
304 static const long ID_CRYSTAL_MENU_PAR_SETRELATIVEXYZLIMITS =WXCRYST_ID();
305 static const long ID_CRYSTAL_MENU_PAR_TEST_RANDOM_MOVES =WXCRYST_ID();
306 static const long ID_CRYSTAL_MENU_SCATT_REMOVESCATTPOW =WXCRYST_ID();
307 static const long ID_CRYSTAL_MENU_SCATT_ADDSCATTPOWATOM =WXCRYST_ID();
308 static const long ID_CRYSTAL_MENU_SCATT_ADDSCATTPOWSPHERE =WXCRYST_ID();
309 static const long ID_CRYSTAL_MENU_SCATT_ADDATOM =WXCRYST_ID();
310 static const long ID_CRYSTAL_MENU_SCATT_IMPORTATOMLIST =WXCRYST_ID();
311 static const long ID_CRYSTAL_MENU_SCATT_ADDZSCATTERER =WXCRYST_ID();
312 static const long ID_CRYSTAL_MENU_SCATT_ADDMOLECULE =WXCRYST_ID();
313 static const long ID_CRYSTAL_MENU_SCATT_ATOMS2MOLECULE =WXCRYST_ID();
314 static const long ID_CRYSTAL_MENU_SCATT_IMPORTFENSKEHALLZMATRIX =WXCRYST_ID();
315 static const long ID_CRYSTAL_MENU_SCATT_IMPORTNAMEDZMATRIX =WXCRYST_ID();
316 static const long ID_CRYSTAL_MENU_SCATT_ADDTETRAHEDRON =WXCRYST_ID();
317 static const long ID_CRYSTAL_MENU_SCATT_ADDOCTAHEDRON =WXCRYST_ID();
318 static const long ID_CRYSTAL_MENU_SCATT_ADDTRIANGLE =WXCRYST_ID();
319 static const long ID_CRYSTAL_MENU_SCATT_ADDSQUAREPLANE =WXCRYST_ID();
320 static const long ID_CRYSTAL_MENU_SCATT_ADDCUBE =WXCRYST_ID();
321 static const long ID_CRYSTAL_MENU_SCATT_ADDANTIPRISMTETRAGONAL =WXCRYST_ID();
322 static const long ID_CRYSTAL_MENU_SCATT_ADDPRISMTRIGONAL =WXCRYST_ID();
323 static const long ID_CRYSTAL_MENU_SCATT_ADDICOSAHEDRON =WXCRYST_ID();
324 static const long ID_CRYSTAL_MENU_SCATT_REMOVESCATTERER =WXCRYST_ID();
325 static const long ID_CRYSTAL_MENU_SCATT_DUPLICSCATTERER =WXCRYST_ID();
326 static const long ID_CRYSTAL_MENU_ADD_INTERMOLECULARDIST =WXCRYST_ID();
327 static const long ID_CRYSTAL_MENU_REMOVE_INTERMOLDIST_WIN =WXCRYST_ID();
328 static const long ID_CRYSTAL_SPACEGROUP =WXCRYST_ID();
329 static const long ID_GLCRYSTAL_MENU_UPDATE =WXCRYST_ID();
330 static const long ID_GLCRYSTAL_WINDOW =WXCRYST_ID();
331 static const long ID_CRYSTAL_WIN_SCATTPOW =WXCRYST_ID();
332 static const long ID_CRYSTAL_WIN_ANTIBUMP =WXCRYST_ID();
333 static const long ID_CRYSTAL_WIN_BONDVALENCE =WXCRYST_ID();
334 static const long ID_CRYSTAL_MENU_SHOW_SCATTPOW_WIN =WXCRYST_ID();
335 static const long ID_CRYSTAL_MENU_SHOW_INTERMOLDIST_WIN =WXCRYST_ID();
336 static const long ID_CRYSTAL_WIN_INTERMOLDIST_EVENT =WXCRYST_ID();
337 //static const long ID_CRYSTAL_MENU_SHOW_PDF =WXCRYST_ID();
338 
339 static const long ID_GLCRYSTAL_FOURIER_ADD= WXCRYST_ID();
340 static const long ID_GLCRYSTAL_FOURIER_REMOVE= WXCRYST_ID();
341 static const long ID_GLCRYSTAL_FOURIER_UPDATE= WXCRYST_ID();
342 static const long ID_GLCRYSTAL_FOURIER_WIREFRAME= WXCRYST_ID();
343 static const long ID_GLCRYSTAL_FOURIER_SHOW= WXCRYST_ID();
344 static const long ID_GLCRYSTAL_FOURIER_SHARPEN= WXCRYST_ID();
345 static const long ID_GLCRYSTAL_FOURIER_LISTMAP= WXCRYST_ID();
346 static const long ID_GLCRYSTAL_FOURIER_LISTGLMAP= WXCRYST_ID();
347 static const long ID_GLCRYSTAL_FOURIER_CONTOUR= WXCRYST_ID();
348 static const long ID_GLCRYSTAL_FOURIER_NEWCONTOUR= WXCRYST_ID();
349 static const long ID_GLCRYSTAL_FOURIER_COLOURPICKER= WXCRYST_ID();
350 
351 
352 BEGIN_EVENT_TABLE(WXCrystal,wxWindow)
353  EVT_BUTTON(ID_WXOBJ_COLLAPSE, WXCrystObj::OnToggleCollapse)
354  EVT_MENU(ID_REFOBJ_MENU_OBJ_SAVE, WXRefinableObj::OnMenuSave)
355  EVT_MENU(ID_REFOBJ_MENU_OBJ_LOAD, WXRefinableObj::OnMenuLoad)
356  EVT_MENU(ID_CRYSTAL_MENU_SAVECIF, WXCrystal::OnMenuSaveCIF)
357  EVT_MENU(ID_CRYSTAL_MENU_SAVETEXT, WXCrystal::OnMenuSaveText)
358  EVT_MENU(ID_REFOBJ_MENU_PAR_FIXALL, WXRefinableObj::OnMenuFixAllPar)
359  EVT_MENU(ID_REFOBJ_MENU_PAR_UNFIXALL, WXRefinableObj::OnMenuUnFixAllPar)
360  EVT_MENU(ID_REFOBJ_MENU_PAR_RANDOMIZE, WXRefinableObj::OnMenuParRandomize)
361  EVT_MENU(ID_CRYSTAL_MENU_PAR_SETRELATIVEXYZLIMITS, WXCrystal::OnMenuSetRelativeXYZLimits)
362  EVT_MENU(ID_CRYSTAL_MENU_PAR_TEST_RANDOM_MOVES, WXCrystal::OnMenuTestRandomMoves)
363 #ifdef OBJCRYST_GL
364  EVT_MENU(ID_CRYSTAL_MENU_DISPLAY_3DVIEW, WXCrystal::OnMenuCrystalGL)
365 #endif
366  EVT_MENU(ID_CRYSTAL_MENU_SCATT_ADDSCATTPOWATOM, WXCrystal::OnMenuAddScattPowAtom)
367  EVT_MENU(ID_CRYSTAL_MENU_SCATT_ADDSCATTPOWSPHERE, WXCrystal::OnMenuAddScattPowSphere)
368  EVT_MENU(ID_CRYSTAL_MENU_SCATT_REMOVESCATTPOW, WXCrystal::OnMenuRemoveScattPow)
369  EVT_MENU(ID_CRYSTAL_MENU_SCATT_ADDATOM, WXCrystal::OnMenuAddScatterer)
370  EVT_MENU(ID_CRYSTAL_MENU_SCATT_IMPORTATOMLIST, WXCrystal::OnMenuAddScatterer)
371  EVT_MENU(ID_CRYSTAL_MENU_SCATT_ADDZSCATTERER, WXCrystal::OnMenuAddScatterer)
372  EVT_MENU(ID_CRYSTAL_MENU_SCATT_ADDMOLECULE, WXCrystal::OnMenuAddScatterer)
373  EVT_MENU(ID_CRYSTAL_MENU_SCATT_ATOMS2MOLECULE, WXCrystal::OnMenuAtoms2Molecule)
374  EVT_MENU(ID_CRYSTAL_MENU_SCATT_IMPORTFENSKEHALLZMATRIX,WXCrystal::OnMenuImportMoleculeFromFenskeHallZMatrix)
375  EVT_MENU(ID_CRYSTAL_MENU_SCATT_IMPORTNAMEDZMATRIX, WXCrystal::OnMenuImportMoleculeFromFenskeHallZMatrix)
376  EVT_MENU(ID_CRYSTAL_MENU_SCATT_ADDTETRAHEDRON, WXCrystal::OnMenuAddScatterer)
377  EVT_MENU(ID_CRYSTAL_MENU_SCATT_ADDOCTAHEDRON, WXCrystal::OnMenuAddScatterer)
378  EVT_MENU(ID_CRYSTAL_MENU_SCATT_ADDTRIANGLE, WXCrystal::OnMenuAddScatterer)
379  EVT_MENU(ID_CRYSTAL_MENU_SCATT_ADDSQUAREPLANE, WXCrystal::OnMenuAddScatterer)
380  EVT_MENU(ID_CRYSTAL_MENU_SCATT_ADDCUBE, WXCrystal::OnMenuAddScatterer)
381  EVT_MENU(ID_CRYSTAL_MENU_SCATT_ADDANTIPRISMTETRAGONAL,WXCrystal::OnMenuAddScatterer)
382  EVT_MENU(ID_CRYSTAL_MENU_SCATT_ADDPRISMTRIGONAL, WXCrystal::OnMenuAddScatterer)
383  EVT_MENU(ID_CRYSTAL_MENU_SCATT_ADDICOSAHEDRON, WXCrystal::OnMenuAddScatterer)
384  EVT_MENU(ID_CRYSTAL_MENU_ADD_INTERMOLECULARDIST, WXCrystal::OnMenuAddIntermolecularDistRestr)
385  EVT_MENU(ID_CRYSTAL_MENU_REMOVE_INTERMOLDIST_WIN, WXCrystal::OnMenuRemoveIntermolecularDistRestr)
386  EVT_MENU(ID_CRYSTAL_MENU_SCATT_REMOVESCATTERER, WXCrystal::OnMenuRemoveScatterer)
387  EVT_MENU(ID_CRYSTAL_MENU_SCATT_DUPLICSCATTERER, WXCrystal::OnMenuDuplicateScatterer)
388  EVT_MENU(ID_CRYSTAL_MENU_SHOW_SCATTPOW_WIN, WXCrystal::OnMenuShowScattPowWindow)
389  EVT_MENU(ID_CRYSTAL_MENU_SHOW_INTERMOLDIST_WIN, WXCrystal::OnMenuShowIntermoDistWindow)
390  EVT_UPDATE_UI(ID_CRYST_UPDATEUI, WXRefinableObj::OnUpdateUI)
391  EVT_GRID_CMD_CELL_CHANGED(ID_CRYSTAL_WIN_SCATTPOW, WXCrystal::OnEditGridScattPow)
392  EVT_GRID_CMD_CELL_CHANGED(ID_CRYSTAL_WIN_ANTIBUMP, WXCrystal::OnEditGridScattPowAntiBump)
393  EVT_GRID_CMD_CELL_CHANGED(ID_CRYSTAL_WIN_BONDVALENCE,WXCrystal::OnEditGridScattPowBondValence)
394  EVT_GRID_CMD_CELL_CHANGED(ID_CRYSTAL_WIN_INTERMOLDIST_EVENT, WXCrystal::OnEditGridIntermolDistWindow)
395 // EVT_MENU(ID_CRYSTAL_MENU_SHOW_PDF, WXCrystal::OnMenuPDF)
396 END_EVENT_TABLE()
397 
398 WXCrystal::WXCrystal(wxWindow* parent, Crystal *obj):
399 WXRefinableObj(parent,(RefinableObj*)obj),mpCrystal(obj),
400 mpScattPowWin(0),mpAntiBumpWin(0),mpBondValenceWin(0),mpIntermolDistWin(0),
401 mIsSelfUpdating(false)
402 #ifdef OBJCRYST_GL
403 ,mCrystalGLDisplayList(0),mCrystalGLNameDisplayList(0),
404 mpCrystalGL(0)
405 #endif
406 ,mpConditionGLUpdate(0)
407 //,mpPDF(0)
408 {
409  VFN_DEBUG_ENTRY("WXCrystal::WXCrystal()",6)
410  //this->SetBackgroundColour("Red");
411  //mpWXTitle->SetBackgroundColour(wxColour(255,200,200));
412  mpWXTitle->SetForegroundColour(wxColour(255,0,0));
413  // Menu
414  mpMenuBar->AddMenu("File",ID_REFOBJ_MENU_OBJ);
415  //mpMenuBar->AddMenuItem(ID_REFOBJ_MENU_OBJ,ID_REFOBJ_MENU_OBJ_LOAD,"Load");
416  //mpMenuBar->AddMenuItem(ID_REFOBJ_MENU_OBJ,ID_REFOBJ_MENU_OBJ_SAVE,"Save");
417  mpMenuBar->AddMenuItem(ID_REFOBJ_MENU_OBJ,ID_CRYSTAL_MENU_SAVETEXT,"Save as text");
418  mpMenuBar->AddMenuItem(ID_REFOBJ_MENU_OBJ,ID_CRYSTAL_MENU_SAVECIF,"Save as CIF");
419  mpMenuBar->AddMenu("Parameters",ID_REFOBJ_MENU_PAR);
420  mpMenuBar->AddMenuItem(ID_REFOBJ_MENU_PAR,ID_REFOBJ_MENU_PAR_FIXALL,"Fix all");
421  mpMenuBar->AddMenuItem(ID_REFOBJ_MENU_PAR,ID_REFOBJ_MENU_PAR_UNFIXALL,"Unfix all");
422  mpMenuBar->AddMenuItem(ID_REFOBJ_MENU_PAR,ID_REFOBJ_MENU_PAR_RANDOMIZE,
423  "Randomize Configuration");
424  mpMenuBar->AddMenuItem(ID_REFOBJ_MENU_PAR,ID_CRYSTAL_MENU_PAR_SETRELATIVEXYZLIMITS,
425  "Set Relative Limits On All XYZ Parameters");
426  mpMenuBar->GetMenu(ID_REFOBJ_MENU_PAR).AppendSeparator();
427  mpMenuBar->AddMenuItem(ID_REFOBJ_MENU_PAR,ID_CRYSTAL_MENU_PAR_TEST_RANDOM_MOVES,
428  "Test Random Moves for 30s");
429  mpMenuBar->AddMenu("Scatterers",ID_CRYSTAL_MENU_SCATT);
430  mpMenuBar->AddMenuItem(ID_CRYSTAL_MENU_SCATT,ID_CRYSTAL_MENU_SHOW_SCATTPOW_WIN,
431  "Show Scattering Powers Parameters Window");
432  mpMenuBar->GetMenu(ID_CRYSTAL_MENU_SCATT).AppendSeparator();
433  mpMenuBar->AddMenuItem(ID_CRYSTAL_MENU_SCATT,ID_CRYSTAL_MENU_SCATT_ADDSCATTPOWATOM,
434  "Add Atomic Scattering Power");
435  mpMenuBar->AddMenuItem(ID_CRYSTAL_MENU_SCATT,ID_CRYSTAL_MENU_SCATT_ADDSCATTPOWSPHERE,
436  "Add Sphere Scattering Power");
437  mpMenuBar->AddMenuItem(ID_CRYSTAL_MENU_SCATT,ID_CRYSTAL_MENU_SCATT_REMOVESCATTPOW,
438  "Remove Scattering Power");
439  mpMenuBar->GetMenu(ID_CRYSTAL_MENU_SCATT).AppendSeparator();
440  mpMenuBar->AddMenuItem(ID_CRYSTAL_MENU_SCATT,ID_CRYSTAL_MENU_SCATT_ADDATOM,
441  "Add Atom");
442  mpMenuBar->AddMenuItem(ID_CRYSTAL_MENU_SCATT,ID_CRYSTAL_MENU_SCATT_IMPORTATOMLIST,
443  "Import a List of Atoms");
444  mpMenuBar->AddMenuItem(ID_CRYSTAL_MENU_SCATT,ID_CRYSTAL_MENU_SCATT_ADDMOLECULE,
445  "Add Molecule");
446  mpMenuBar->AddMenuItem(ID_CRYSTAL_MENU_SCATT,ID_CRYSTAL_MENU_SCATT_ATOMS2MOLECULE,
447  "Convert Atoms to a Molecule");
448  mpMenuBar->AddMenuItem(ID_CRYSTAL_MENU_SCATT,ID_CRYSTAL_MENU_SCATT_IMPORTFENSKEHALLZMATRIX,
449  "Import Molecule from Fenske-Hall Z-Matrix");
450  mpMenuBar->AddMenuItem(ID_CRYSTAL_MENU_SCATT,ID_CRYSTAL_MENU_SCATT_IMPORTNAMEDZMATRIX,
451  "Import Molecule from a named Z-Matrix");
452  mpMenuBar->AddMenuItem(ID_CRYSTAL_MENU_SCATT,ID_CRYSTAL_MENU_SCATT_REMOVESCATTERER,
453  "Remove Scatterer");
454  mpMenuBar->AddMenuItem(ID_CRYSTAL_MENU_SCATT,ID_CRYSTAL_MENU_SCATT_DUPLICSCATTERER,
455  "Duplicate Scatterer");
456  mpMenuBar->GetMenu(ID_CRYSTAL_MENU_SCATT).AppendSeparator();
457  mpMenuBar->AddMenuItem(ID_CRYSTAL_MENU_SCATT,ID_CRYSTAL_MENU_SCATT_ADDTETRAHEDRON,
458  "Add Tetrahedron");
459  mpMenuBar->AddMenuItem(ID_CRYSTAL_MENU_SCATT,ID_CRYSTAL_MENU_SCATT_ADDOCTAHEDRON,
460  "Add Octahedron");
461  mpMenuBar->AddMenuItem(ID_CRYSTAL_MENU_SCATT,ID_CRYSTAL_MENU_SCATT_ADDTRIANGLE,
462  "Add Triangle Plane");
463  mpMenuBar->AddMenuItem(ID_CRYSTAL_MENU_SCATT,ID_CRYSTAL_MENU_SCATT_ADDSQUAREPLANE,
464  "Add Square Plane");
465  mpMenuBar->AddMenuItem(ID_CRYSTAL_MENU_SCATT,ID_CRYSTAL_MENU_SCATT_ADDCUBE,
466  "Add Cube");
467  mpMenuBar->AddMenuItem(ID_CRYSTAL_MENU_SCATT,
468  ID_CRYSTAL_MENU_SCATT_ADDANTIPRISMTETRAGONAL,
469  "Add Antiprism Tetragonal");
470  mpMenuBar->AddMenuItem(ID_CRYSTAL_MENU_SCATT,ID_CRYSTAL_MENU_SCATT_ADDPRISMTRIGONAL,
471  "Add Prism Trigonal");
472  mpMenuBar->AddMenuItem(ID_CRYSTAL_MENU_SCATT,ID_CRYSTAL_MENU_SCATT_ADDICOSAHEDRON,
473  "Add Icosahedron");
474  mpMenuBar->GetMenu(ID_CRYSTAL_MENU_SCATT).AppendSeparator();
475  mpMenuBar->AddMenuItem(ID_CRYSTAL_MENU_SCATT,ID_CRYSTAL_MENU_ADD_INTERMOLECULARDIST,
476  "Add Intermolecular Distance Restraint");
477  mpMenuBar->AddMenuItem(ID_CRYSTAL_MENU_SCATT,ID_CRYSTAL_MENU_SHOW_INTERMOLDIST_WIN,
478  "Show Intermolecular Distance Restraints");
479  mpMenuBar->AddMenuItem(ID_CRYSTAL_MENU_SCATT,ID_CRYSTAL_MENU_REMOVE_INTERMOLDIST_WIN,
480  "Remove Intermolecular Distance Restraints");
481 
482 
483  mpMenuBar->AddMenu("Display",ID_CRYSTAL_MENU_DISPLAY);
484  mpMenuBar->AddMenuItem(ID_CRYSTAL_MENU_DISPLAY,ID_CRYSTAL_MENU_DISPLAY_3DVIEW,
485  "3D Display");
486  //mpMenuBar->AddMenuItem(ID_CRYSTAL_MENU_DISPLAY,ID_CRYSTAL_MENU_SHOW_PDF,
487  // "PDF");
488 
489  //mpSizer->SetItemMinSize(mpMenuBar,
490  // mpMenuBar->GetSize().GetWidth(),
491  // mpMenuBar->GetSize().GetHeight());
492 
493  // KLUDGE : this only works as long as the option order does not change !
494  dynamic_cast<WXFieldOption *>(mpCrystal->GetOption(0).WXGet())->SetToolTip(
495  _T("Use this option ONLY if you want to use\n")
496  _T("a higher symmetry than the one allowed by\n")
497  _T("the spacegroup. This can be useful to search\n")
498  _T("structures derived from higher symmetries.\n\n")
499  _T("This option should almost never be used."));
500 
501  dynamic_cast<WXFieldOption *>(mpCrystal->GetOption(1).WXGet())->SetToolTip(
502  _T("This option allows Fox to automatically adjust\n")
503  _T("the occupancy of atoms that are on a special position,\n")
504  _T("or overlapping with another (e.g. two oxygens from\n")
505  _T("two polyhedra).\n\n")
506  _T("Practically you should choose:\n")
507  _T("- Yes for inorganic structures\n")
508  _T("- No for organic structures\n\n")
509  _T("This option increases computing time\n")
510  _T("by up to 50%, so only use when necessary\n\n")
511  _T("In doubt, choose Yes"));
512 
513  dynamic_cast<WXFieldOption *>(mpCrystal->GetOption(2).WXGet())->SetToolTip(
514  _T("This option only affects the 3D display,\n")
515  _T("and is used to display the enantiomer\n")
516  _T("of the crystal structure.\n\n")
517  _T("This can be used to compare several\n")
518  _T("crystal structures."));
519 
520 
521  // AntiBump-ProMerge cost
522  wxBoxSizer* pAntiBumpSizer=new wxBoxSizer(wxHORIZONTAL);
523  WXFieldPar<REAL> *pWXFieldBumpMerge=
524  new WXFieldPar<REAL>(this,"AntiBump",-1,&(mpCrystal->mBumpMergeCost),100);
525  WXFieldPar<REAL> *pAntiBumpScale=
526  new WXFieldPar<REAL>(this,"Scale",-1,&(mpCrystal->mBumpMergeScale));
527  pAntiBumpSizer->Add(pWXFieldBumpMerge);
528  pAntiBumpSizer->Add(pAntiBumpScale);
529  mpSizer->Add(pAntiBumpSizer,0,wxALIGN_LEFT);
530  mList.Add(pWXFieldBumpMerge);
531  mList.Add(pAntiBumpScale);
532  pWXFieldBumpMerge->SetFormat(_T("%8.2f"));
533  pAntiBumpScale->SetFormat(_T("%8.2f"));
534  pWXFieldBumpMerge->SetToolTip(_T("Current anti-bump cost"));
535  pAntiBumpScale->SetToolTip(
536  _T("Scale (multiplier) for the anti-bump cost.\n")
537  _T("If 0, the anti-bump will be ignored and not calculated\n")
538  _T("during optimization (saving time)\n\n")
539  _T("Use a value larger than 1 to increase the importance\n")
540  _T("of the anti-bump relatively to the diffraction data Chi^2\n\n")
541  _T("Note that anti-bump should only be used if the diffraction data\n\n")
542  _T("is not of good enough quality to ensure finding the correct\n\n")
543  _T("structure."));
544  // Bond Valence cost
545  wxBoxSizer* pBondValenceSizer=new wxBoxSizer(wxHORIZONTAL);
546  WXFieldPar<REAL> *pWXFieldBondValence=
547  new WXFieldPar<REAL>(this,"Bond Valence Cost",-1,&(mpCrystal->mBondValenceCost),100);
548  WXFieldPar<REAL> *pBondValenceScale=
549  new WXFieldPar<REAL>(this,"Scale",-1,&(mpCrystal->mBondValenceCostScale));
550  pBondValenceSizer->Add(pWXFieldBondValence);
551  pBondValenceSizer->Add(pBondValenceScale);
552  mpSizer->Add(pBondValenceSizer,0,wxALIGN_LEFT);
553  mList.Add(pWXFieldBondValence);
554  mList.Add(pBondValenceScale);
555  pWXFieldBondValence->SetFormat(_T("%8.2f"));
556  pBondValenceScale->SetFormat(_T("%8.2f"));
557  pWXFieldBondValence->SetToolTip(_T("Current bond valence cost"));
558  pBondValenceScale->SetToolTip(
559  _T("Scale (multiplier) for the bond valence cost.\n")
560  _T("If 0, the bond valence will be ignored and not calculated\n")
561  _T("during optimization (saving time)\n\n")
562  _T("Use a value larger than 1 to increase the importance\n")
563  _T("of the bond valence relatively to the diffraction data Chi^2\n\n")
564  _T("Note that bond valence should only be used if the diffraction data\n\n")
565  _T("is not of good enough quality to ensure finding the correct\n\n")
566  _T("structure."));
567  // Intermolecular distance cost
568  wxBoxSizer* pInterMolDistSizer=new wxBoxSizer(wxHORIZONTAL);
569  WXFieldPar<REAL> *pWXFieldInterMoldDistCost=
570  new WXFieldPar<REAL>(this,"Inter-molecular Distance Cost",-1,&(mpCrystal->mInterMolDistCost),100);
571  WXFieldPar<REAL> *pInterMoleDistScale=
572  new WXFieldPar<REAL>(this,"Scale",-1,&(mpCrystal->mInterMolDistCostScale));
573  pInterMolDistSizer->Add(pWXFieldInterMoldDistCost);
574  pInterMolDistSizer->Add(pInterMoleDistScale);
575  mpSizer->Add(pInterMolDistSizer,0,wxALIGN_LEFT);
576  mList.Add(pWXFieldInterMoldDistCost);
577  mList.Add(pInterMoleDistScale);
578  pWXFieldInterMoldDistCost->SetFormat(_T("%8.2f"));
579  pInterMoleDistScale->SetFormat(_T("%8.2f"));
580  pWXFieldInterMoldDistCost->SetToolTip(_T("Current Inter-molecular Distance cost"));
581  pInterMoleDistScale->SetToolTip(
582  _T("Scale (multiplier) for the inter-molecular distance cost.\n")
583  _T("If 0, the user-defined inter-molecular distances will be ignored and not calculated\n")
584  _T("during optimization (saving time)\n\n")
585  _T("Use a value larger than 1 to increase the importance\n")
586  _T("of the bond valence relatively to the diffraction data Chi^2.\n\n"));
587 
588  // Lattice
589  wxBoxSizer* lattice=new wxBoxSizer(wxHORIZONTAL);
590 
591  WXCrystObjBasic* pFieldLatticeA
592  =mpCrystal->GetPar("a").WXCreate(this);
593  WXCrystObjBasic* pFieldLatticeB
594  =mpCrystal->GetPar("b").WXCreate(this);
595  WXCrystObjBasic* pFieldLatticeC
596  =mpCrystal->GetPar("c").WXCreate(this);
597  WXCrystObjBasic* pFieldLatticeAlpha
598  =mpCrystal->GetPar("alpha").WXCreate(this);
599  WXCrystObjBasic* pFieldLatticeBeta
600  =mpCrystal->GetPar("beta").WXCreate(this);
601  WXCrystObjBasic* pFieldLatticeGamma
602  =mpCrystal->GetPar("gamma").WXCreate(this);
603 
604  lattice->Add(pFieldLatticeA ,0,wxALIGN_CENTER|wxRESERVE_SPACE_EVEN_IF_HIDDEN);
605  lattice->Add(pFieldLatticeB ,0,wxALIGN_CENTER|wxRESERVE_SPACE_EVEN_IF_HIDDEN);
606  lattice->Add(pFieldLatticeC ,0,wxALIGN_CENTER|wxRESERVE_SPACE_EVEN_IF_HIDDEN);
607  lattice->Add(pFieldLatticeAlpha,0,wxALIGN_CENTER|wxRESERVE_SPACE_EVEN_IF_HIDDEN);
608  lattice->Add(pFieldLatticeBeta ,0,wxALIGN_CENTER|wxRESERVE_SPACE_EVEN_IF_HIDDEN);
609  lattice->Add(pFieldLatticeGamma,0,wxALIGN_CENTER|wxRESERVE_SPACE_EVEN_IF_HIDDEN);
610  lattice->Layout();
611 
612  mpSizer->Add(lattice,0,wxALIGN_LEFT);
613  mList.Add(pFieldLatticeA);
614  mList.Add(pFieldLatticeB);
615  mList.Add(pFieldLatticeC);
616  mList.Add(pFieldLatticeAlpha);
617  mList.Add(pFieldLatticeBeta);
618  mList.Add(pFieldLatticeGamma);
619 
620  dynamic_cast<WXFieldRefPar *>(pFieldLatticeA)->SetFormat(_T("%8.4f"));
621  dynamic_cast<WXFieldRefPar *>(pFieldLatticeB)->SetFormat(_T("%8.4f"));
622  dynamic_cast<WXFieldRefPar *>(pFieldLatticeC)->SetFormat(_T("%8.4f"));
623  dynamic_cast<WXFieldRefPar *>(pFieldLatticeAlpha)->SetFormat(_T("%8.3f"));
624  dynamic_cast<WXFieldRefPar *>(pFieldLatticeBeta)->SetFormat(_T("%8.3f"));
625  dynamic_cast<WXFieldRefPar *>(pFieldLatticeGamma)->SetFormat(_T("%8.3f"));
626 
627  pFieldLatticeA->SetToolTip(_T("Lattice length parameter (in Angstroems)"));
628  pFieldLatticeB->SetToolTip(_T("Lattice length parameter (in Angstroems)"));
629  pFieldLatticeC->SetToolTip(_T("Lattice length parameter (in Angstroems)"));
630  pFieldLatticeAlpha->SetToolTip(_T("Lattice angle parameter (in degrees)"));
631  pFieldLatticeBeta->SetToolTip(_T("Lattice angle parameter (in degrees)"));
632  pFieldLatticeGamma->SetToolTip(_T("Lattice angle parameter (in degrees)"));
633 
634  // SpaceGroup
635  mpFieldSpacegroup=new WXFieldName(this,"SpaceGroup:",this,ID_CRYSTAL_SPACEGROUP,100);
636  mpSizer->Add(mpFieldSpacegroup,0,wxALIGN_LEFT);
637  mList.Add(mpFieldSpacegroup);
638 
639  mpFieldSpacegroup->SetToolTip(_T("Spacegroup Symbol. You can use:\n\n")
640  _T("- spacegroup number: \"1\" \"62\" ... \"227\",\"230\"\n")
641  _T("- Hermann-Mauguin symbol: \"P1\" \"Pnma\" ... \"Fd3m\",\"Ia3d\"\n")
642  _T("- Hall symbol: \"P1\" \"-P 2ac 2n\" ... \"-F 4vw 2vw 3\",\"-I 4bd 2c 3\"\n\n")
643  _T("ORIGIN CHOICE: for some spacegroups there are several\n")
644  _T("possible origins - the default is the one on \n")
645  _T("the center of symmetry (origin 2). You can specify\n")
646  _T(" the origin by writing \"Fd3m:1\" or \"Fd3m:2\"\n\n")
647  _T("CELL CHOICE: to specify a rhomboedral or hexagonal unit cell,\n")
648  _T("append R or H to the symbol:\"R-3:R\"or \"R-3:H\"\n"));
649 
650  // Scattering Powers
651  mpWXScatteringPowerRegistry=mpCrystal
652  ->GetScatteringPowerRegistry().WXCreate(this);
653  mpSizer->Add(mpWXScatteringPowerRegistry,0,wxALIGN_LEFT);
654  mList.Add(mpWXScatteringPowerRegistry);
655 
656  // Scatterers
657  mpWXScattererRegistry=mpCrystal
658  ->GetScattererRegistry().WXCreate(this);
659  mpSizer->Add(mpWXScattererRegistry,0,wxALIGN_LEFT);
660  mList.Add(mpWXScattererRegistry);
661  this->CrystUpdate(true);
662  {
663  bool val;
664  if(!wxConfigBase::Get()->HasEntry(_T("Crystal/BOOL/Automatically open crystal 3D view")))
665  wxConfigBase::Get()->Write(_T("Crystal/BOOL/Automatically open crystal 3D view"), false);
666  else
667  {
668  wxConfigBase::Get()->Read(_T("Crystal/BOOL/Automatically open crystal 3D view"), &val);
669  if(val)
670  {
671  (*fpObjCrystInformUser)("Automatically opening 3D Crystal view");
672  wxCommandEvent event(wxEVT_COMMAND_MENU_SELECTED,ID_CRYSTAL_MENU_DISPLAY_3DVIEW);
673  wxPostEvent(this,event);
674  (*fpObjCrystInformUser)("Finished opening 3D Crystal view");
675  }
676  }
677  }
678  wxTheApp->GetTopWindow()->PostSizeEvent();
679  VFN_DEBUG_EXIT("WXCrystal::WXCrystal()",6)
680 }
681 
682 WXCrystal::~WXCrystal()
683 {
684  VFN_DEBUG_ENTRY("WXCrystal::~WXCrystal()",10)
685  if(0!=mpScattPowWin) mpScattPowWin->GetParent()->Destroy();
686  if(0!=mpIntermolDistWin) mpIntermolDistWin->GetParent()->Destroy();
687  VFN_DEBUG_EXIT("WXCrystal::~WXCrystal()",10)
688 }
689 
690 void WXCrystal::CrystUpdate(const bool uui,const bool lock)
691 {
692  VFN_DEBUG_ENTRY("WXCrystal::CrystUpdate()",5)
693 
694  wxWakeUpIdle();
695  mpCrystal->GetBumpMergeCost();
696  mpCrystal->GetBondValenceCost();
697  mpCrystal->GetInterMolDistCost();
698  #ifdef OBJCRYST_GL
699  if(mpCrystalGL!=0)
700  {
701  if(lock) mMutex.Lock();
702  BBox box=mpCrystalGL->GetCellBBox();
703  const REAL fadeDistance=mpCrystalGL->GetFadeDistance();
704  if(lock) mMutex.Unlock();
705  bool showFullMolecule;
706  wxConfigBase::Get()->Read(_T("Crystal/BOOL/Show full molecules in 3D view"), &showFullMolecule);
707 
708  this->UpdateGL(false,box.xMin,box.xMax,box.yMin,box.yMax,box.zMin,box.zMax,fadeDistance, showFullMolecule);
709  }
710  #endif
711  if(lock) mMutex.Lock();
712  // Necessary to change the "used" status of unit cell parameters.
713  if((false==this->GetCrystal().IsBeingRefined()) && wxThread::IsMain() ) this->GetCrystal().InitRefParList();
714 
715  //if((false==this->GetCrystal().IsBeingRefined()) && wxThread::IsMain() &&(mpIntermolDistWin!=0)) {
716  // bool needLayout=false;
717  //}
718 
719  if((false==this->GetCrystal().IsBeingRefined()) && wxThread::IsMain() &&(mpScattPowWin!=0)&&(mpAntiBumpWin!=0)&&(mpBondValenceWin!=0))
720  {
721  //set<ScatteringPowerAtom*> vpRemovedScattPow;
722  //set<ScatteringPowerAtom*> vpAddedScattPow;
723 
724  bool needLayout=false;
725  // Delete rows & cols as required
726  for(map<ScatteringPowerAtom*,RowScattPow>::iterator pos=mvpRowScattPow.begin();pos!=mvpRowScattPow.end();)
727  if(this->GetCrystal().GetScatteringPowerRegistry().Find(pos->second.mName,"ScatteringPowerAtom",true)<0)
728  {
729  VFN_DEBUG_MESSAGE("WXCrystal::CrystUpdate(): Removing scattering power: "<<pos->second.mName,5)
730  mpScattPowWin->DeleteRows(mvpRowScattPow.size()-1,1,false);
731  mpAntiBumpWin->DeleteRows(mvpRowScattPow.size()-1,1,false);
732  mpBondValenceWin->DeleteRows(mvpRowScattPow.size()-1,1,false);
733  mpAntiBumpWin->DeleteCols(mvpRowScattPow.size()-1,1,false);
734  mpBondValenceWin->DeleteCols(mvpRowScattPow.size()-1,1,false);
735  mvpRowScattPow.erase(pos++);
736  needLayout=true;
737  }
738  else ++pos; // See Josuttis, p.205
739  // Add rows & cols as required
740  for(int i=0;i<this->GetCrystal().GetScatteringPowerRegistry().GetNb();++i)
741  {
742  ScatteringPower *s=&(this->GetCrystal().GetScatteringPowerRegistry().GetObj(i));
743  if(s->GetClassName()=="ScatteringPowerAtom")
744  {
745  ScatteringPowerAtom *p=dynamic_cast<ScatteringPowerAtom *>(s);
746  if(mvpRowScattPow.find(p)==mvpRowScattPow.end())
747  {
748  VFN_DEBUG_MESSAGE("WXCrystal::CrystUpdate(): Adding scattering power: "<<s->GetName(),5)
749  mpScattPowWin->AppendRows();
750  mpAntiBumpWin->AppendRows();
751  mpAntiBumpWin->AppendCols();
752  mpBondValenceWin->AppendRows();
753  mpBondValenceWin->AppendCols();
754  mvpRowScattPow.insert(make_pair(p,RowScattPow()));
755  needLayout=true;
756  }
757  }
758  }
759  // Put the scattering powers in the same order as they have been declared,
760  // for user convenience
761  {
762  int j=0; // :KLUDGE: number of scattering powers that are not ScatteringPowerAtom
763  for(int i=0;i<this->GetCrystal().GetScatteringPowerRegistry().GetNb();++i)
764  {
765  ScatteringPower *s=&(this->GetCrystal().GetScatteringPowerRegistry().GetObj(i));
766  if(s->GetClassName()=="ScatteringPowerAtom")
767  {
768  ScatteringPowerAtom *p=dynamic_cast<ScatteringPowerAtom *>(s);
769  if(mvpRowScattPow[p].mIdx!=i-j)
770  {
771  mvpRowScattPow[p].mIdx=i-j;
772  mvpRowScattPow[p].mNeedUpdateUI=true;
773  }
774  }
775  else j++;
776  }
777  }
778  if(needLayout)
779  {
780  mpScattPowWin->FitInside();
781  mpAntiBumpWin->FitInside();
782  mpBondValenceWin->FitInside();
783  }
784  // Update windows
785  //if(mpScattPowWin!=0)
786  {
787  map<ScatteringPowerAtom*,RowScattPow>::iterator pos;
788  for(pos=mvpRowScattPow.begin();pos!=mvpRowScattPow.end();++pos)
789  {
790  const string name=pos->first->GetName();
791  const REAL biso=pos->first->GetBiso();
792  const REAL formalCharge=pos->first->GetFormalCharge();
793  const float *pRGB=pos->first->GetColourRGB();
794  const REAL mlerror=pos->first->GetMaximumLikelihoodPositionError();
795  const REAL nbghost=pos->first->GetMaximumLikelihoodNbGhostAtom();
796  if( (name !=pos->second.mName)
797  ||(biso !=pos->second.mBiso)
798  ||(formalCharge!=pos->second.mFormalCharge)
799  ||(pRGB[0]!=pos->second.mR)
800  ||(pRGB[1]!=pos->second.mG)
801  ||(pRGB[2]!=pos->second.mB)
802  ||(mlerror!=pos->second.mMaximumLikelihoodError)
803  ||(nbghost!=pos->second.mNbGhostAtoms)
804  || pos->second.mNeedUpdateUI)
805  {
806  pos->second.mName=name;
807  pos->second.mBiso=biso;
808  pos->second.mFormalCharge=formalCharge;
809  pos->second.mR=pRGB[0];
810  pos->second.mG=pRGB[1];
811  pos->second.mB=pRGB[2];
812  pos->second.mMaximumLikelihoodError=mlerror;
813  pos->second.mNbGhostAtoms=nbghost;
814  pos->second.mNeedUpdateUI=true;
815  }
816  }
817  }
818  //if(mpAntiBumpWin!=0)
819  {
820  map<ScatteringPowerAtom*,RowScattPow>::iterator pos,pos1;
821  for(pos=mvpRowScattPow.begin();pos!=mvpRowScattPow.end();++pos)
822  {
823  const string name=pos->first->GetName();
824  const Crystal::VBumpMergePar *pMap=&(mpCrystal->GetBumpMergeParList());
825  vector<REAL> dist(mvpRowScattPow.size());
826  for(pos1=mvpRowScattPow.begin();pos1!=mvpRowScattPow.end();++pos1)
827  {
828  Crystal::VBumpMergePar::const_iterator pos2;
829  if(pos->first<pos1->first) pos2=pMap->find(make_pair(pos->first,pos1->first));
830  else pos2=pMap->find(make_pair(pos1->first,pos->first));
831  if(pos2==pMap->end()) dist[pos1->second.mIdx]=-999;
832  else dist[pos1->second.mIdx]=sqrt(pos2->second.mDist2);
833  }
834  if( (name!=pos->second.mName)
835  ||(dist!=pos->second.mvAntiBumpDistance)
836  || pos->second.mNeedUpdateUI)
837  {
838  pos->second.mName=name;
839  pos->second.mvAntiBumpDistance=dist;
840  pos->second.mNeedUpdateUI=true;
841  }
842  }
843  }
844  //if(mpBondValenceWin!=0)
845  {
846  map<ScatteringPowerAtom*,RowScattPow>::iterator pos,pos1;
847  for(pos=mvpRowScattPow.begin();pos!=mvpRowScattPow.end();++pos)
848  {
849  const string name=pos->first->GetName();
850  const std::map<pair<const ScatteringPower*,const ScatteringPower*>, REAL> *pMap=&(mpCrystal->GetBondValenceRoList());
851  vector<REAL> ro(mvpRowScattPow.size());
852  for(pos1=mvpRowScattPow.begin();pos1!=mvpRowScattPow.end();++pos1)
853  {
854  map<pair<const ScatteringPower*,const ScatteringPower*>, REAL>::const_iterator pos2;
855  if(pos->first<pos1->first) pos2=pMap->find(make_pair(pos->first,pos1->first));
856  else pos2=pMap->find(make_pair(pos1->first,pos->first));
857  if(pos2==pMap->end()) ro[pos1->second.mIdx]=-999;
858  else ro[pos1->second.mIdx]=pos2->second;
859  }
860  if( (name!=pos->second.mName)
861  ||(ro!=pos->second.mvBondValenceRo)
862  || pos->second.mNeedUpdateUI)
863  {
864  pos->second.mName=name;
865  pos->second.mvBondValenceRo=ro;
866  pos->second.mNeedUpdateUI=true;
867  }
868  }
869  }
870  }
871  if(lock) mMutex.Unlock();
872 
873  this->WXRefinableObj::CrystUpdate(uui,lock);
874  VFN_DEBUG_EXIT("WXCrystal::CrystUpdate():End",5)
875 }
876 
877 #ifdef OBJCRYST_GL
878 void WXCrystal::UpdateGL(const bool onlyIndependentAtoms,
879  const REAL xMin,const REAL xMax,
880  const REAL yMin,const REAL yMax,
881  const REAL zMin,const REAL zMax,
882  const REAL fadeDistance,
883  const bool fullMoleculeInLimits)
884 {
885  // :KLUDGE: !!! UGLY !!! This should be done in WXGLCrystalCanvas !
886  VFN_DEBUG_ENTRY("WXCrystal::UpdateGL()",8)
887  WXCrystValidateAllUserInput();
888  if(mpCrystalGL!=0)
889  {
890  VFN_DEBUG_MESSAGE("WXCrystal::UpdateGL():mpCrystalGL",7)
891  if(false==wxThread::IsMain())
892  {
893  mpConditionGLUpdate=new wxCondition(mMutexGLUpdate);
894  bool ok=mpConditionGLUpdate->IsOk();
895  mMutexGLUpdate.Lock();
896  wxCommandEvent event(wxEVT_COMMAND_MENU_SELECTED,ID_GLCRYSTAL_MENU_UPDATE);
897  wxPostEvent(mpCrystalGL,event);
898  wxWakeUpIdle();
899  wxThread::This()->Yield();
900  int ct=0;
901  while(mpConditionGLUpdate->WaitTimeout(200)!=wxCOND_NO_ERROR)
902  {
903  cout<<"WXCrystal::UpdateGL():timeout waiting for mpConditionGLUpdate release: #"<<++ct<<":"<<ok<<endl;
904  wxWakeUpIdle();
905  if(ct>10) break;//and hope for the best...
906  }
907  mMutexGLUpdate.Unlock();
908  delete mpConditionGLUpdate;
909  mpConditionGLUpdate=0;
910  VFN_DEBUG_EXIT("WXCrystal::UpdateGL()-Not in main thread :End",8)
911  return;
912  }
913  mpCrystalGL->SetCurrent();
914  if(mCrystalGLDisplayList==0)
915  {
916  mCrystalGLDisplayList=glGenLists(1);
917  mCrystalGLNameDisplayList=glGenLists(1);
918  VFN_DEBUG_MESSAGE("WXCrystal::UpdateGL():created mCrystalGLDisplayList=" << mCrystalGLDisplayList << ",mCrystalGLNameDisplayList=" << mCrystalGLNameDisplayList, 10)
919  }
920  glNewList(mCrystalGLDisplayList,GL_COMPILE);
921  glPushMatrix();
922  mpCrystal->GLInitDisplayList(onlyIndependentAtoms,xMin,xMax,yMin,yMax,zMin,zMax,false,!(mpCrystalGL->GetShowHydrogens()),fadeDistance,fullMoleculeInLimits);
923  //ScatteringPowerMap map1(mpCrystal->GetScatteringPowerRegistry().GetObj(0),
924  // *mpCrystal,.02,.05,.05,RAD_XRAY);
925  //map1.GLInitDisplayList(xMin,xMax,yMin,yMax,zMin,zMax);
926  //UnitCellScattererDensityMap map2(*mpCrystal,21,21,21);
927  //cout << map2.GetMap3D()<<endl;
928  //map2.GLInitDisplayList(xMin,xMax,yMin,yMax,zMin,zMax);
929  glPopMatrix();
930  glEndList();
931  glNewList(mCrystalGLNameDisplayList,GL_COMPILE);
932  glPushMatrix();
933  mpCrystal->GLInitDisplayList(onlyIndependentAtoms,xMin,xMax,yMin,yMax,zMin,zMax,true,!(mpCrystalGL->GetShowHydrogens()),fadeDistance,fullMoleculeInLimits);
934  glPopMatrix();
935  glEndList();
936  mpCrystalGL->CrystUpdate();
937  if(mpConditionGLUpdate!=0)
938  {
939  wxMutexLocker lock(mMutexGLUpdate);
940  mpConditionGLUpdate->Signal();
941  }
942  }
943  else
944  {
945  VFN_DEBUG_MESSAGE("WXCrystal::UpdateGL():No mpCrystalGL",7)
946  }
947  VFN_DEBUG_EXIT("WXCrystal::UpdateGL():End",8)
948 }
949 
950 int WXCrystal::GetCrystalGLDisplayList(const bool atomName)const
951 {
952  VFN_DEBUG_MESSAGE("WXCrystal::GetCrystalGLDisplayList()",7)
953  if(atomName) return mCrystalGLNameDisplayList;
954  return mCrystalGLDisplayList;
955 }
956 
957 class WXGLCrystalCanvasFrame :public wxFrame
958 {
959  public:
960  WXGLCrystalCanvasFrame(wxWindow *parent, wxWindowID id, const wxString& title, const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize, long style = wxDEFAULT_FRAME_STYLE, const wxString& name = wxFrameNameStr) :
961  wxFrame(parent, id, title, pos, size, style, name)
962  {}
963  ~WXGLCrystalCanvasFrame()
964  {
965  gvWindowPosition[ID_GLCRYSTAL_WINDOW] = make_pair(this->GetScreenPosition(), this->GetSize());
966  //VFN_DEBUG_MESSAGE("~ @(" << gvWindowPosition[ID_GLCRYSTAL_WINDOW].first.x << "," << gvWindowPosition[ID_GLCRYSTAL_WINDOW].first.y << ")",10)
967  }
968 };
969 
970 void WXCrystal::OnMenuCrystalGL(wxCommandEvent & WXUNUSED(event))
971 {
972  VFN_DEBUG_MESSAGE("WXCrystal::OnMenuCrystalGL()",6)
973  if(mpCrystalGL!=0) return;
974  wxFrame* frame;
975  if (gvWindowPosition.count(ID_GLCRYSTAL_WINDOW))
976  {
977  //cout << "WXCrystal::OnMenuCrystalGL():@(" << gvWindowPosition[ID_GLCRYSTAL_WINDOW].first.x << "," << gvWindowPosition[ID_GLCRYSTAL_WINDOW].first.y << ")" << endl;
978  frame = new WXGLCrystalCanvasFrame(this, ID_GLCRYSTAL_WINDOW, wxString::Format("%s [%s]",mpCrystal->GetName().c_str(), mpCrystal->GetSpaceGroup().GetName().c_str()),
979  gvWindowPosition[ID_GLCRYSTAL_WINDOW].first,
980  gvWindowPosition[ID_GLCRYSTAL_WINDOW].second, wxCLOSE_BOX | wxRESIZE_BORDER | wxCAPTION | wxMINIMIZE_BOX | wxMAXIMIZE_BOX);//wxFRAME_FLOAT_ON_PARENT
981  }
982  else
983  frame = new WXGLCrystalCanvasFrame(this, ID_GLCRYSTAL_WINDOW, wxString::Format("%s [%s]",mpCrystal->GetName().c_str(), mpCrystal->GetSpaceGroup().GetName().c_str()),
984  wxDefaultPosition, wxSize(400, 400), wxCLOSE_BOX | wxRESIZE_BORDER | wxCAPTION | wxMINIMIZE_BOX | wxMAXIMIZE_BOX);//wxFRAME_FLOAT_ON_PARENT
985 
986  mpCrystalGL=new WXGLCrystalCanvas(this,frame,-1);
987  #if wxUSE_STATUSBAR
988  frame->CreateStatusBar(1);
989  frame->SetStatusText(wxString::Format("%s [%s]",mpCrystal->GetName().c_str(), mpCrystal->GetSpaceGroup().GetName().c_str()));
990  #endif
991 
992  frame->Show(true);
993  frame->Raise();
994  //The contents to be displayed will be generated on the first OnPaint event, in InitGL
995 }
996 void WXCrystal::NotifyCrystalGLDelete()
997 {
998  VFN_DEBUG_MESSAGE("WXCrystal::NotifyCrystalGLDelete()",7)
999  mpCrystalGL=0;
1000 }
1001 WXGLCrystalCanvas * WXCrystal::GetCrystalGL()
1002 {
1003  VFN_DEBUG_MESSAGE("WXCrystal::GetCrystalGL()",7)
1004  return mpCrystalGL;
1005 }
1006 #endif
1007 
1008 void WXCrystal::OnMenuSaveCIF(wxCommandEvent & WXUNUSED(event))
1009 {
1011  wxFileDialog save(this,_T("Choose a file"),_T(""),_T(""),_T("*.cif"),wxFD_SAVE | wxFD_OVERWRITE_PROMPT);
1012  if(save.ShowModal() != wxID_OK) return;
1013 
1014  ofstream out(save.GetPath().ToAscii());
1015  if(!out) return;//:TODO:
1016  mpCrystal->CIFOutput(out);
1017  out.close();
1018 }
1019 
1020 void WXCrystal::OnMenuSaveText(wxCommandEvent & WXUNUSED(event))
1021 {
1023  wxFileDialog save(this,_T("Choose a file"),_T(""),_T(""),_T("*.txt"),wxFD_SAVE | wxFD_OVERWRITE_PROMPT);
1024  if(save.ShowModal() != wxID_OK) return;
1025 
1026  ofstream out(save.GetPath().ToAscii());
1027  if(!out) return;//:TODO:
1028  mpCrystal->Print(out);
1029  mpCrystal->PrintMinDistanceTable(.05,out);
1030  out.close();
1031 }
1032 
1033 void WXCrystal::OnMenuAddScattPowAtom(wxCommandEvent & WXUNUSED(event))
1034 {
1035  VFN_DEBUG_MESSAGE("WXCrystal::OnMenuAddScattPowAtom()",6)
1036  WXCrystValidateAllUserInput();
1037  ScatteringPowerAtom *scatt=new ScatteringPowerAtom("Change me","H");
1038  mpCrystal->AddScatteringPower(scatt);
1039  VFN_DEBUG_MESSAGE("WXCrystal::OnMenuAddScattPowAtom():End",6)
1040  this->Layout();
1041  this->CrystUpdate(true,false);
1042  wxTheApp->GetTopWindow()->Layout();
1043  wxTheApp->GetTopWindow()->SendSizeEvent();
1044 }
1045 
1046 void WXCrystal::OnMenuAddScattPowSphere(wxCommandEvent & WXUNUSED(event))
1047 {
1048  VFN_DEBUG_ENTRY("WXCrystal::OnMenuAddScattSphere()",6)
1049  WXCrystValidateAllUserInput();
1050  ScatteringPower *scatt= new ScatteringPowerSphere;
1051  mpCrystal->AddScatteringPower(scatt);
1052  this->Layout();
1053  this->CrystUpdate(true,false);
1054  VFN_DEBUG_EXIT("WXCrystal::OnMenuAddScattPowSphere()",6)
1055  wxTheApp->GetTopWindow()->Layout();
1056  wxTheApp->GetTopWindow()->SendSizeEvent();
1057 }
1058 
1059 void WXCrystal::OnMenuRemoveScattPow(wxCommandEvent & WXUNUSED(event))
1060 {
1061  VFN_DEBUG_ENTRY("WXCrystal::OnButtonRemoveScattPow()",6)
1062  WXCrystValidateAllUserInput();
1063  int choice;
1064  ScatteringPower *scatt=
1065  WXDialogChooseFromRegistry(mpCrystal->GetScatteringPowerRegistry(),this,
1066  "Choose Scattering Power to remove:",choice);
1067  if(0==scatt)
1068  {
1069  VFN_DEBUG_EXIT("WXCrystal::OnButtonRemoveScattPow():Cancelled",6)
1070  return;
1071  }
1072  const ScatteringComponentList *pList=&(mpCrystal->GetScatteringComponentList());
1073  for(long i=0;i<pList->GetNbComponent();++i)
1074  if((*pList)(i).mpScattPow==scatt)
1075  {
1076  wxMessageDialog dumbUser(this,_T("This Scattering Power is still used !"),
1077  _T("Whooops"),wxOK|wxICON_EXCLAMATION);
1078  dumbUser.ShowModal();
1079  VFN_DEBUG_EXIT("WXCrystal::OnButtonRemoveScattPow()",6)
1080  return;
1081  }
1082  mpCrystal->RemoveScatteringPower(scatt);
1083  VFN_DEBUG_EXIT("WXCrystal::OnButtonRemoveScattPow()",6)
1084  this->Layout();
1085  this->CrystUpdate(true,false);
1086  wxTheApp->GetTopWindow()->Layout();
1087  wxTheApp->GetTopWindow()->SendSizeEvent();
1088 }
1089 void WXCrystal::OnMenuRemoveIntermolecularDistRestr(wxCommandEvent & event)
1090 {//OnMenuShowIntermoDistWindow
1092 
1093  wxArrayString choices;
1094  choices.resize(mpCrystal->GetIntermolDistNb());
1095  for(int i=0;i<choices.size();i++) {
1096  Crystal::InterMolDistPar imdp = mpCrystal->GetIntermolDistPar(i);
1097  string myline;
1098  for(int j=0;j<imdp.mAt1.size();j++) {
1099  myline += imdp.mAt1[j] + " ";
1100  }
1101  myline += "-> ";
1102  for(int j=0;j<imdp.mAt2.size();j++) {
1103  myline += imdp.mAt2[j] + " ";
1104  }
1105 
1106  choices[i] = myline;
1107  }
1108 
1109  wxSingleChoiceDialog dialog(this,_T("Choose restraints you want to delete"),_T("Select line"),choices);
1110  if(wxID_OK!=dialog.ShowModal()) return;
1111  int pos = dialog.GetSelection();
1112 
1113  mpCrystal->RemoveIntermolDistPar(pos);
1114  wxMessageDialog dialog5(this, _T("The restriction was removed"));
1115  dialog5.ShowModal();
1116 
1117  wxTheApp->GetTopWindow()->Layout();
1118  wxTheApp->GetTopWindow()->SendSizeEvent();
1119 }
1120 void WXCrystal::OnMenuAddIntermolecularDistRestr(wxCommandEvent & event)
1121 {
1122 
1123  VFN_DEBUG_ENTRY("WXMolecule::OnMenuAddBond()",6)
1124  WXCrystValidateAllUserInput();
1125  int choice;
1126  const vector<Crystal::NamedScatteringComponent> pList=mpCrystal->GetNamedScatteringComponentList();
1127 
1128  wxArrayString choices;
1129  choices.resize(pList.size());
1130  for(unsigned int i=0;i<pList.size();i++)
1131  choices[i]= wxString::FromAscii(pList[i].mName.c_str());
1132 
1133  wxMultiChoiceDialog dialog(this,_T("Choose name(s) of the first atom(s)"),_T("Select Atom(s)"),choices);
1134  if(wxID_OK!=dialog.ShowModal()) return;
1135  wxArrayInt At1=dialog.GetSelections();
1136  if((At1.size()==0) || (At1.size()>=pList.size())) return;
1137 
1138  wxMultiChoiceDialog dialog1(this,_T("Choose name(s) of the second atom(s)"),_T("Select Atom(s)"),choices);
1139  if(wxID_OK!=dialog1.ShowModal()) return;
1140  wxArrayInt At2=dialog1.GetSelections();
1141  if((At2.size()==0) || (At2.size()>=pList.size())) return;
1142 
1143  string tmpAt1;
1144  vector<string> vectAt1;
1145  for(int i=0;i<At1.size();i++) {
1146  tmpAt1 += choices[At1[i]];
1147  vectAt1.push_back(choices[At1[i]].ToStdString());
1148  if(i<(At1.size()-1)) {
1149  tmpAt1 += " ";
1150  }
1151  }
1152 
1153  string tmpAt2;
1154  vector<string> vectAt2;
1155  for(int i=0;i<At2.size();i++) {
1156  tmpAt2 += choices[At2[i]];
1157  vectAt2.push_back(choices[At2[i]].ToStdString());
1158  if(i<(At2.size()-1)) {
1159  tmpAt2 += " ";
1160  }
1161  }
1162  string mes = "Enter bond distance (Angstroems) for "+ tmpAt1 + " - " + tmpAt2;
1163  wxTextEntryDialog dialog2(this,wxString::FromAscii(mes.c_str()),
1164  _T("Intermolecular bond distance"),"3.5",wxOK | wxCANCEL);
1165  dialog2.SetTextValidator(wxTextValidator(wxFILTER_NUMERIC));
1166  if(wxID_OK!=dialog2.ShowModal()) return;
1167  double d;
1168  dialog2.GetValue().ToDouble(&d);
1169 
1170  wxTextEntryDialog dialog3(this,_T("Enter sigma"),
1171  _T("Sigma"),"0.1",wxOK | wxCANCEL);
1172  dialog3.SetTextValidator(wxTextValidator(wxFILTER_NUMERIC));
1173  if(wxID_OK!=dialog3.ShowModal()) return;
1174  double sigma;
1175  dialog3.GetValue().ToDouble(&sigma);
1176 
1177  wxTextEntryDialog dialog4(this,_T("Enter Delta"),
1178  _T("Delta"),"0.5",wxOK | wxCANCEL);
1179  dialog4.SetTextValidator(wxTextValidator(wxFILTER_NUMERIC));
1180  if(wxID_OK!=dialog4.ShowModal()) return;
1181  double delta;
1182  dialog4.GetValue().ToDouble(&delta);
1183 
1184  mpCrystal->SetNewInterMolDist(vectAt1, vectAt2, d, sigma, delta);
1185 
1186  wxMessageDialog dialog5(this, _T("The restriction was added"));
1187  dialog5.ShowModal();
1188 
1189  wxTheApp->GetTopWindow()->Layout();
1190  wxTheApp->GetTopWindow()->SendSizeEvent();
1191 
1192 }
1193 void WXCrystal::OnMenuAddScatterer(wxCommandEvent &event)
1194 {
1195  VFN_DEBUG_ENTRY("WXCrystal::OnMenuAddScatterer()",6)
1196  WXCrystValidateAllUserInput();
1197  Scatterer *scatt=0;
1198  if(event.GetId()== ID_CRYSTAL_MENU_SCATT_ADDATOM)
1199  {
1200  int choice;
1201  ScatteringPower *scattPow=
1202  WXDialogChooseFromRegistry(mpCrystal->GetScatteringPowerRegistry(),this,
1203  "Choose an atom type (ScatteringPower):",choice);
1204  if(0==scattPow)
1205  {
1206  VFN_DEBUG_EXIT("WXCrystal::OnMenuAddScatterer():Canceled",6)
1207  return;
1208  }
1209  scatt=new Atom(0,0,0,"Change Me!",scattPow);
1210  }
1211  if(event.GetId()== ID_CRYSTAL_MENU_SCATT_IMPORTATOMLIST)
1212  {
1213  wxFileDialog open(this,_T("Choose a file with a list of atoms: Element x y z occup"),_T(""),_T(""),_T("*"),
1214  wxFD_OPEN | wxFD_FILE_MUST_EXIST);
1215  if(open.ShowModal() != wxID_OK) return;
1216  ifstream fin (open.GetPath().ToAscii());
1217  if(!fin)
1218  {
1219  throw ObjCrystException("WXCrystal::OnMenuAddScatterer() : Error opening file for input:"+string(open.GetPath().ToAscii()));
1220  }
1221  string symbol;
1222  REAL x,y,z,occup;
1223  int n=1;
1224  char buf [10];
1225  int scattPow;
1226  while(true)
1227  {
1228  fin>>symbol;
1229  if(fin.eof()) break;
1230  fin>>x>>y>>z>>occup;
1231  cout<<symbol<<n<<": "<<x<<", "<<y<<", "<<z<<endl;
1232  scattPow=mpCrystal->GetScatteringPowerRegistry().Find(symbol,"ScatteringPowerAtom",true);
1233  if(scattPow<0)
1234  {
1235  cout<<"Scattering power "<<symbol<<" not found, creating it..."<<endl;
1236  mpCrystal->AddScatteringPower(new ScatteringPowerAtom(symbol,symbol));
1237  }
1238  sprintf(buf,"%d",n++);
1239  mpCrystal->AddScatterer(new Atom(x,y,z,symbol+(string)buf,&(mpCrystal->GetScatteringPower(symbol)),occup));
1240  if(fin.eof()) break;
1241  }
1242  fin.close();
1243  scatt=0;
1244  }
1245  if(event.GetId()== ID_CRYSTAL_MENU_SCATT_ADDZSCATTERER)
1246  {
1247  scatt=new ZScatterer("Change Me!",*mpCrystal);
1248  }
1249  if(event.GetId()== ID_CRYSTAL_MENU_SCATT_ADDMOLECULE)
1250  {
1251  scatt=new Molecule(*mpCrystal,"Molecule");
1252  }
1253  if(event.GetId()== ID_CRYSTAL_MENU_SCATT_ADDTETRAHEDRON)
1254  {
1255 
1256  int choice;
1257  //Scattering power 1
1258  const ScatteringPower *scattPow1=WXDialogChooseFromRegistry(
1259  mpCrystal->GetScatteringPowerRegistry(),
1260  this,"Central atom type (ScatteringPower):",choice);
1261  if(0==scattPow1)
1262  {
1263  VFN_DEBUG_EXIT("WXCrystal::OnMenuAddScatterer():Canceled",6)
1264  return;
1265  }
1266  //Scattering power 2
1267  const ScatteringPower *scattPow2=WXDialogChooseFromRegistry(
1268  mpCrystal->GetScatteringPowerRegistry(),
1269  this,"Corner atom type (ScatteringPower):",choice);
1270  if(0==scattPow2)
1271  {
1272  VFN_DEBUG_EXIT("WXCrystal::OnMenuAddScatterer():Canceled",6)
1273  return;
1274  }
1275  //Bond length
1276  wxTextEntryDialog bondLengthDialog(this,_T("Bond length"),
1277  _T("Enter bond length (Angstroems)"),_T("1"),wxOK | wxCANCEL);
1278  bondLengthDialog.SetTextValidator(wxTextValidator(wxFILTER_NUMERIC));
1279  if(wxID_OK!=bondLengthDialog.ShowModal())
1280  {
1281  VFN_DEBUG_EXIT("WXZScatterer))OnMenuAddZAtom())Cancelled",6)
1282  return;
1283  }
1284  double bondLength;
1285  bondLengthDialog.GetValue().ToDouble(&bondLength);
1286 
1287  Molecule *mol=MakeTetrahedron(*mpCrystal,scattPow1->GetName()+scattPow2->GetName()+"4",
1288  scattPow1,scattPow2,bondLength);
1289  mol->RestraintStatus(cout);
1290  scatt=mol;
1291  }
1292  if(event.GetId()== ID_CRYSTAL_MENU_SCATT_ADDOCTAHEDRON)
1293  {
1294  int choice;
1295  //Scattering power 1
1296  const ScatteringPower *scattPow1=WXDialogChooseFromRegistry(
1297  mpCrystal->GetScatteringPowerRegistry(),
1298  this,"Central atom type (ScatteringPower):",choice);
1299  if(0==scattPow1)
1300  {
1301  VFN_DEBUG_EXIT("WXCrystal::OnMenuAddScatterer():Canceled",6)
1302  return;
1303  }
1304  //Scattering power 2
1305  const ScatteringPower *scattPow2=WXDialogChooseFromRegistry(
1306  mpCrystal->GetScatteringPowerRegistry(),
1307  this,"Corner atom type (ScatteringPower))",choice);
1308  if(0==scattPow2)
1309  {
1310  VFN_DEBUG_EXIT("WXCrystal::OnMenuAddScatterer():Canceled",6)
1311  return;
1312  }
1313  //Bond length
1314  wxTextEntryDialog bondLengthDialog(this,_T("Bond length"),
1315  _T("Enter bond length (Angstroems)"),_T("1"),wxOK | wxCANCEL);
1316  bondLengthDialog.SetTextValidator(wxTextValidator(wxFILTER_NUMERIC));
1317  if(wxID_OK!=bondLengthDialog.ShowModal())
1318  {
1319  VFN_DEBUG_EXIT("WXZScatterer))OnMenuAddZAtom())Cancelled",6)
1320  return;
1321  }
1322  double bondLength;
1323  bondLengthDialog.GetValue().ToDouble(&bondLength);
1324 
1325  Molecule *mol=MakeOctahedron(*mpCrystal,scattPow1->GetName()+scattPow2->GetName()+"6",
1326  scattPow1,scattPow2,bondLength);
1327  mol->RestraintStatus(cout);
1328  scatt=mol;
1329  }
1330  if(event.GetId()== ID_CRYSTAL_MENU_SCATT_ADDTRIANGLE)
1331  {
1332  VFN_DEBUG_MESSAGE("WXCrystal::OnMenuAddScatterer())Add triangle plane",6)
1333  int choice;
1334  //Scattering power 1
1335  const ScatteringPower *scattPow1=WXDialogChooseFromRegistry(
1336  mpCrystal->GetScatteringPowerRegistry(),
1337  this,"Central atom type (ScatteringPower))",choice);
1338  if(0==scattPow1)
1339  {
1340  VFN_DEBUG_EXIT("WXCrystal::OnMenuAddScatterer():Canceled",6)
1341  return;
1342  }
1343  //Scattering power 2
1344  const ScatteringPower *scattPow2=WXDialogChooseFromRegistry(
1345  mpCrystal->GetScatteringPowerRegistry(),
1346  this,"Corner atom type (ScatteringPower))",choice);
1347  if(0==scattPow2)
1348  {
1349  VFN_DEBUG_EXIT("WXCrystal::OnMenuAddScatterer():Canceled",6)
1350  return;
1351  }
1352  //Bond length
1353  wxTextEntryDialog bondLengthDialog(this,_T("Bond length"),
1354  _T("Enter bond length (Angstroems)"),_T("1"),wxOK | wxCANCEL);
1355  bondLengthDialog.SetTextValidator(wxTextValidator(wxFILTER_NUMERIC));
1356  if(wxID_OK!=bondLengthDialog.ShowModal())
1357  {
1358  VFN_DEBUG_EXIT("WXZScatterer::OnMenuAddZAtom():Cancelled",6)
1359  return;
1360  }
1361  double bondLength;
1362  bondLengthDialog.GetValue().ToDouble(&bondLength);
1363 
1364  Molecule *mol=MakeTriangle(*mpCrystal,scattPow1->GetName()+scattPow2->GetName()+"3",
1365  scattPow1,scattPow2,bondLength);
1366  mol->RestraintStatus(cout);
1367  scatt=mol;
1368  }
1369  if(event.GetId()== ID_CRYSTAL_MENU_SCATT_ADDSQUAREPLANE)
1370  {
1371  VFN_DEBUG_MESSAGE("WXCrystal::OnMenuAddScatterer():Add square plane",6)
1372  int choice;
1373  //Scattering power 1
1374  const ScatteringPower *scattPow1=WXDialogChooseFromRegistry(
1375  mpCrystal->GetScatteringPowerRegistry(),
1376  this,"Central atom type (ScatteringPower))",choice);
1377  if(0==scattPow1)
1378  {
1379  VFN_DEBUG_EXIT("WXCrystal::OnMenuAddScatterer():Canceled",6)
1380  return;
1381  }
1382  //Scattering power 2
1383  const ScatteringPower *scattPow2=WXDialogChooseFromRegistry(
1384  mpCrystal->GetScatteringPowerRegistry(),
1385  this,"Corner atom type (ScatteringPower))",choice);
1386  if(0==scattPow2)
1387  {
1388  VFN_DEBUG_EXIT("WXCrystal::OnMenuAddScatterer():Canceled",6)
1389  return;
1390  }
1391  //Bond length
1392  wxTextEntryDialog bondLengthDialog(this,_T("Bond length"),
1393  _T("Enter bond length (Angstroems)"),_T("1"),wxOK | wxCANCEL);
1394  bondLengthDialog.SetTextValidator(wxTextValidator(wxFILTER_NUMERIC));
1395  if(wxID_OK!=bondLengthDialog.ShowModal())
1396  {
1397  VFN_DEBUG_EXIT("WXZScatterer::OnMenuAddZAtom():Cancelled",6)
1398  return;
1399  }
1400  double bondLength;
1401  bondLengthDialog.GetValue().ToDouble(&bondLength);
1402 
1403  Molecule *mol=MakeSquarePlane(*mpCrystal,scattPow1->GetName()+scattPow2->GetName()+"4",
1404  scattPow1,scattPow2,bondLength);
1405  mol->RestraintStatus(cout);
1406  scatt=mol;
1407  }
1408  if(event.GetId()== ID_CRYSTAL_MENU_SCATT_ADDCUBE)
1409  {
1410  int choice;
1411  //Scattering power 1
1412  const ScatteringPower *scattPow1=WXDialogChooseFromRegistry(
1413  mpCrystal->GetScatteringPowerRegistry(),
1414  this,"Central atom type (ScatteringPower):",choice);
1415  if(0==scattPow1)
1416  {
1417  VFN_DEBUG_EXIT("WXCrystal::OnMenuAddScatterer():Canceled",6)
1418  return;
1419  }
1420  //Scattering power 2
1421  const ScatteringPower *scattPow2=WXDialogChooseFromRegistry(
1422  mpCrystal->GetScatteringPowerRegistry(),
1423  this,"Corner atom type (ScatteringPower))",choice);
1424  if(0==scattPow2)
1425  {
1426  VFN_DEBUG_EXIT("WXCrystal::OnMenuAddScatterer():Canceled",6)
1427  return;
1428  }
1429  //Bond length
1430  wxTextEntryDialog bondLengthDialog(this,_T("Bond length"),
1431  _T("Enter bond length (Angstroems)"),_T("1"),wxOK | wxCANCEL);
1432  bondLengthDialog.SetTextValidator(wxTextValidator(wxFILTER_NUMERIC));
1433  if(wxID_OK!=bondLengthDialog.ShowModal())
1434  {
1435  VFN_DEBUG_EXIT("WXZScatterer::OnMenuAddZAtom():Cancelled",6)
1436  return;
1437  }
1438  double bondLength;
1439  bondLengthDialog.GetValue().ToDouble(&bondLength);
1440 
1441  Molecule *mol=MakeCube(*mpCrystal,scattPow1->GetName()+scattPow2->GetName()+"8",
1442  scattPow1,scattPow2,bondLength);
1443  mol->RestraintStatus(cout);
1444  scatt=mol;
1445  }
1446  if(event.GetId()== ID_CRYSTAL_MENU_SCATT_ADDANTIPRISMTETRAGONAL)
1447  {
1448  int choice;
1449  //Scattering power 1
1450  const ScatteringPower *scattPow1=WXDialogChooseFromRegistry(
1451  mpCrystal->GetScatteringPowerRegistry(),
1452  this,"Central atom type (ScatteringPower):",choice);
1453  if(0==scattPow1)
1454  {
1455  VFN_DEBUG_EXIT("WXCrystal::OnMenuAddScatterer():Canceled",6)
1456  return;
1457  }
1458  //Scattering power 2
1459  const ScatteringPower *scattPow2=WXDialogChooseFromRegistry(
1460  mpCrystal->GetScatteringPowerRegistry(),
1461  this,"Corner atom type (ScatteringPower))",choice);
1462  if(0==scattPow2)
1463  {
1464  VFN_DEBUG_EXIT("WXCrystal::OnMenuAddScatterer():Canceled",6)
1465  return;
1466  }
1467  //Bond length
1468  wxTextEntryDialog bondLengthDialog(this,_T("Bond length"),
1469  _T("Enter bond length (Angstroems)"),_T("1"),wxOK | wxCANCEL);
1470  bondLengthDialog.SetTextValidator(wxTextValidator(wxFILTER_NUMERIC));
1471  if(wxID_OK!=bondLengthDialog.ShowModal())
1472  {
1473  VFN_DEBUG_EXIT("WXZScatterer::OnMenuAddZAtom():Cancelled",6)
1474  return;
1475  }
1476  double bondLength;
1477  bondLengthDialog.GetValue().ToDouble(&bondLength);
1478 
1479  Molecule *mol=MakeAntiPrismTetragonal(*mpCrystal,scattPow1->GetName()+scattPow2->GetName()+"8",
1480  scattPow1,scattPow2,bondLength);
1481  mol->RestraintStatus(cout);
1482  scatt=mol;
1483  }
1484  if(event.GetId()== ID_CRYSTAL_MENU_SCATT_ADDPRISMTRIGONAL)
1485  {
1486  int choice;
1487  //Scattering power 1
1488  const ScatteringPower *scattPow1=WXDialogChooseFromRegistry(
1489  mpCrystal->GetScatteringPowerRegistry(),
1490  this,"Central atom type (ScatteringPower))",choice);
1491  if(0==scattPow1)
1492  {
1493  VFN_DEBUG_EXIT("WXCrystal::OnMenuAddScatterer():Canceled",6)
1494  return;
1495  }
1496  //Scattering power 2
1497  const ScatteringPower *scattPow2=WXDialogChooseFromRegistry(
1498  mpCrystal->GetScatteringPowerRegistry(),
1499  this,"Corner atom type (ScatteringPower))",choice);
1500  if(0==scattPow2)
1501  {
1502  VFN_DEBUG_EXIT("WXCrystal::OnMenuAddScatterer():Canceled",6)
1503  return;
1504  }
1505  //Bond length
1506  wxTextEntryDialog bondLengthDialog(this,_T("Bond length"),
1507  _T("Enter bond length (Angstroems)"),_T("1"),wxOK | wxCANCEL);
1508  bondLengthDialog.SetTextValidator(wxTextValidator(wxFILTER_NUMERIC));
1509  if(wxID_OK!=bondLengthDialog.ShowModal())
1510  {
1511  VFN_DEBUG_EXIT("WXZScatterer::OnMenuAddZAtom())Cancelled",6)
1512  return;
1513  }
1514  double bondLength;
1515  bondLengthDialog.GetValue().ToDouble(&bondLength);
1516 
1517  Molecule *mol=MakePrismTrigonal(*mpCrystal,scattPow1->GetName()+scattPow2->GetName()+"6",
1518  scattPow1,scattPow2,bondLength);
1519  mol->RestraintStatus(cout);
1520  scatt=mol;
1521  }
1522  if(event.GetId()== ID_CRYSTAL_MENU_SCATT_ADDICOSAHEDRON)
1523  {
1524  int choice;
1525  //Scattering power 1
1526  const ScatteringPower *scattPow1=WXDialogChooseFromRegistry(
1527  mpCrystal->GetScatteringPowerRegistry(),
1528  this,"Central atom type (ScatteringPower):",choice);
1529  if(0==scattPow1)
1530  {
1531  VFN_DEBUG_EXIT("WXCrystal::OnMenuAddScatterer():Canceled",6)
1532  return;
1533  }
1534  //Scattering power 2
1535  const ScatteringPower *scattPow2=WXDialogChooseFromRegistry(
1536  mpCrystal->GetScatteringPowerRegistry(),
1537  this,"Corner atom type (ScatteringPower):",choice);
1538  if(0==scattPow2)
1539  {
1540  VFN_DEBUG_EXIT("WXCrystal::OnMenuAddScatterer():Canceled",6)
1541  return;
1542  }
1543  //Bond length
1544  wxTextEntryDialog bondLengthDialog(this,_T("Bond length"),
1545  _T("Enter bond length (Angstroems)"),_T("1"),wxOK | wxCANCEL);
1546  bondLengthDialog.SetTextValidator(wxTextValidator(wxFILTER_NUMERIC));
1547  if(wxID_OK!=bondLengthDialog.ShowModal())
1548  {
1549  VFN_DEBUG_EXIT("WXZScatterer::OnMenuAddZAtom():Cancelled",6)
1550  return;
1551  }
1552  double bondLength;
1553  bondLengthDialog.GetValue().ToDouble(&bondLength);
1554 
1555  Molecule *mol=MakeIcosahedron(*mpCrystal,scattPow1->GetName()+scattPow2->GetName()+"12",
1556  scattPow1,scattPow2,bondLength);
1557  mol->RestraintStatus(cout);
1558  scatt=mol;
1559  }
1560  if(scatt!=0)
1561  {
1562  mpCrystal->AddScatterer(scatt);
1563  mpCrystal->UpdateDisplay();
1564  }
1565  VFN_DEBUG_MESSAGE("WXCrystal::OnMenuAddScatterer():calling Layout()",6)
1566  //this->CrystUpdate();
1567  this->Layout();
1568  wxTheApp->GetTopWindow()->Layout();
1569  wxTheApp->GetTopWindow()->SendSizeEvent();
1570  VFN_DEBUG_EXIT("WXCrystal::OnMenuAddScatterer()",6)
1571 }
1572 
1573 void WXCrystal::OnMenuRemoveScatterer(wxCommandEvent & WXUNUSED(event))
1574 {
1575  VFN_DEBUG_MESSAGE("WXCrystal::OnButtonRemoveScatterer()",6)
1576  WXCrystValidateAllUserInput();
1577  int choice;
1578  Scatterer *scatt=WXDialogChooseFromRegistry(mpCrystal->GetScattererRegistry(),this,
1579  "Select the Scatterer to remove:",choice);
1580  if(0==scatt) return;
1581  mpCrystal->RemoveScatterer(scatt);
1582  VFN_DEBUG_MESSAGE("WXCrystal::OnButtonRemoveScatterer():End",6)
1583  this->Layout();
1584  wxTheApp->GetTopWindow()->Layout();
1585  wxTheApp->GetTopWindow()->SendSizeEvent();
1586  this->CrystUpdate(true);
1587 }
1588 
1589 void WXCrystal::OnMenuDuplicateScatterer(wxCommandEvent & WXUNUSED(event))
1590 {
1591  VFN_DEBUG_ENTRY("WXCrystal::OnMenuDuplicateScatterer()",6)
1592  WXCrystValidateAllUserInput();
1593  int choice;
1594  Scatterer *scatt=WXDialogChooseFromRegistry(mpCrystal->GetScattererRegistry(),this,
1595  "Select the Scatterer to duplicate:",choice);
1596  if(0==scatt) return;
1597  Scatterer *copy=scatt->CreateCopy();
1598  scatt->SetName(scatt->GetName()+(string)"(copy)");
1599  mpCrystal->AddScatterer(copy);
1600  this->Layout();
1601  wxTheApp->GetTopWindow()->Layout();
1602  wxTheApp->GetTopWindow()->SendSizeEvent();
1603  VFN_DEBUG_EXIT("WXCrystal::OnMenuDuplicateScatterer():End",6)
1604 }
1605 
1606 Molecule *ZScatterer2Molecule(ZScatterer *scatt);//defined in wxZScatterer.cpp
1607 
1608 void WXCrystal::OnMenuAtoms2Molecule(wxCommandEvent &event)
1609 {
1610  vector<Atom*> v;
1611  for(unsigned int i=0; i<mpCrystal->GetScattererRegistry().GetNb();++i)
1612  {
1613  Atom *pAtom=dynamic_cast<Atom *>(&(mpCrystal->GetScattererRegistry().GetObj(i)));
1614  if(pAtom!=0) v.push_back(pAtom);
1615  }
1616  const unsigned int nb=v.size();
1617  wxString *choices = new wxString[nb];
1618  for(unsigned int i=0;i<nb;i++)
1619  choices[i]= wxString::FromAscii((v[i]->GetName()).c_str());
1620  #if 0
1621  wxMultiChoiceDialog dialog (this,_T("Choose the molecule's atoms"),_T("Select Atoms"),nb,choices,wxOK | wxCANCEL);
1622  dialog.SetSize(300,300);
1623  #else
1624  wxMultiChoiceDialog_ListBox dialog(this,_T("Choose the molecule's atoms"),_T("Select Atoms"),nb,choices);
1625  #endif
1626  if(wxID_OK!=dialog.ShowModal()) return;
1627  wxArrayInt choice=dialog.GetSelections();
1628  if(choice.GetCount()>0)
1629  {
1630  list<Atom*> vChoice;
1631  for(unsigned int i=0;i<choice.GetCount();++i) vChoice.push_back(v[choice.Item(i)]);
1632 
1633  mpCrystal->AddScatterer(Atoms2Molecule(vChoice));
1634  for(unsigned int i=0;i<choice.GetCount();++i) mpCrystal->RemoveScatterer(v[choice.Item(i)]);
1635  mpCrystal->UpdateDisplay();
1636  }
1637  wxTheApp->GetTopWindow()->Layout();
1638  wxTheApp->GetTopWindow()->SendSizeEvent();
1639 }
1640 
1641 void WXCrystal::OnMenuImportMoleculeFromFenskeHallZMatrix(wxCommandEvent &event)
1642 {
1643  VFN_DEBUG_ENTRY("WXCrystal::OnMenuImportFenskeHallZMatrix()",6)
1644  WXCrystValidateAllUserInput();
1645  string tmp("Fenske-Hall z-matrix|*.fhz;*.fh");
1646  if(event.GetId()==ID_CRYSTAL_MENU_SCATT_IMPORTNAMEDZMATRIX) tmp="Fox z-matrix|*.zmat";
1647  wxFileDialog open(this,_T("Choose a file with a Fenske-Hall Z-matrix"),_T(""),_T(""), wxString::FromAscii(tmp.c_str()),
1648  wxFD_OPEN | wxFD_FILE_MUST_EXIST);
1649  if(open.ShowModal() != wxID_OK) return;
1650  ifstream fin ( open.GetPath().ToAscii());
1651  if(!fin)
1652  {
1653  throw ObjCrystException("WXCrystal::OnMenuImportFenskeHallZMatrix() : \
1654 Error opening file for input:"+string(open.GetPath().ToAscii()));
1655  }
1656  string filename(open.GetPath().ToAscii());
1657  string shortName;
1658  {// Use short name
1659  std::string::size_type idx =filename.rfind("/");
1660  std::string::size_type idx2=filename.rfind("\\");
1661  std::string::size_type idx3=filename.rfind(":");
1662  if(((long)idx2!=(long)string::npos)&&((long)idx2>(long)idx))idx=idx2;
1663  if(((long)idx3!=(long)string::npos)&&((long)idx3>(long)idx))idx=idx3;
1664  if(idx==string::npos)
1665  shortName=filename;
1666  else
1667  shortName=filename.substr(idx+1);
1668  }
1669  ZScatterer scatt(shortName,*mpCrystal);
1670  bool named=false;
1671  if(event.GetId()==ID_CRYSTAL_MENU_SCATT_IMPORTNAMEDZMATRIX) named=true;
1672  scatt.ImportFenskeHallZMatrix(fin,named);
1673  fin.close();
1674  mpCrystal->AddScatterer(ZScatterer2Molecule(&scatt));
1675  wxTheApp->GetTopWindow()->Layout();
1676  wxTheApp->GetTopWindow()->SendSizeEvent();
1677  this->CrystUpdate(true);
1678  VFN_DEBUG_EXIT("WXCrystal::OnMenuImportFenskeHallZMatrix()",6)
1679 }
1680 
1681 void WXCrystal::OnMenuSetRelativeXYZLimits(wxCommandEvent & WXUNUSED(event))
1682 {
1683  VFN_DEBUG_ENTRY("WXCrystal::OnMenuSetRelativeXYZLimits():Cancelled",6)
1684  WXCrystValidateAllUserInput();
1685  wxTextEntryDialog limitDialog(this,_T("Relative limits"),
1686  _T("Enter relative limits for x,y,z (Angstroems)"),
1687  _T("0.5"),wxOK | wxCANCEL);
1688  limitDialog.SetTextValidator(wxTextValidator(wxFILTER_NUMERIC));
1689  if(wxID_OK!=limitDialog.ShowModal())
1690  {
1691  VFN_DEBUG_EXIT("WXCrystal::OnMenuSetRelativeXYZLimits():Cancelled",6)
1692  return;
1693  }
1694  double limit;
1695  limitDialog.GetValue().ToDouble(&limit);
1696  limit=fabs(limit);
1697 
1698  mpCrystal->SetLimitsRelative(gpRefParTypeScattTranslX,
1699  -limit/mpCrystal->GetLatticePar(0),
1700  limit/mpCrystal->GetLatticePar(0));
1701  mpCrystal->SetLimitsRelative(gpRefParTypeScattTranslY,
1702  -limit/mpCrystal->GetLatticePar(1),
1703  limit/mpCrystal->GetLatticePar(1));
1704  mpCrystal->SetLimitsRelative(gpRefParTypeScattTranslZ,
1705  -limit/mpCrystal->GetLatticePar(2),
1706  limit/mpCrystal->GetLatticePar(2));
1707  VFN_DEBUG_EXIT("WXCrystal::OnMenuSetRelativeXYZLimits()",6)
1708 }
1709 
1711 class TestCrystalThread: public wxThread
1712 {
1713  public:
1714  TestCrystalThread(Crystal &cryst,float seconds):
1715  wxThread(wxTHREAD_DETACHED),mpCryst(&cryst),mSeconds(seconds){};
1716  virtual void *Entry()
1717  {
1718  cout<<endl<<"Entering refinement thread "<<endl<<endl;
1719  mpCryst->BeginOptimization();
1720  Chronometer chrono;
1721  float dt0=chrono.seconds();
1722  while(chrono.seconds()<30)
1723  {
1724  mpCryst->BeginGlobalOptRandomMove();
1725  mpCryst->GlobalOptRandomMove(0.05,gpRefParTypeObjCryst);
1726  wxMilliSleep(1);// Slow down display for simple structures
1727  if((chrono.seconds()-dt0)>0.05) {mpCryst->UpdateDisplay();dt0=chrono.seconds();}
1728  }
1729  mpCryst->EndOptimization();
1730  return NULL;
1731  };
1732  virtual void OnExit()
1733  {
1734  cout <<endl<<"Exiting refinement thread "<<endl<<endl;
1735  };
1736  private:
1738  Crystal *mpCryst;
1740  float mSeconds;
1741 };
1742 
1743 void WXCrystal::OnMenuTestRandomMoves(wxCommandEvent &event)
1744 {
1745  TestCrystalThread *pTest = new TestCrystalThread(*mpCrystal,30);
1746  if(pTest->Create() != wxTHREAD_NO_ERROR)
1747  wxLogError(_T("Can't create test optimization thread"));
1748  else pTest->Run();
1749 }
1750 
1751 bool WXCrystal::OnChangeName(const int id)
1752 {
1753  VFN_DEBUG_MESSAGE("WXCrystal::OnChangeName()",6)
1754  if(this->WXRefinableObj::OnChangeName(id)==true) return true;
1755  if(id==ID_CRYSTAL_SPACEGROUP)
1756  {
1757  VFN_DEBUG_MESSAGE("WXCrystal::OnChangeName():Changing SpaceGroup",6)
1758  mpCrystal->Init(mpCrystal->GetLatticePar(0),
1759  mpCrystal->GetLatticePar(1),
1760  mpCrystal->GetLatticePar(2),
1761  mpCrystal->GetLatticePar(3),
1762  mpCrystal->GetLatticePar(4),
1763  mpCrystal->GetLatticePar(5),
1764  mpFieldSpacegroup->GetValue(),
1765  mpCrystal->GetName());
1766  this->CrystUpdate(true);
1767  this->Layout();
1768  return true;
1769  }
1770  return false;
1771 }
1772 
1773 void WXCrystal::UpdateUI(const bool lock)
1774 {
1775  VFN_DEBUG_ENTRY("WXCrystal::UpdateUI()",6)
1776  if(!mpCrystal->IsBeingRefined())
1777  {
1778  if(lock) mMutex.Lock();
1779  mpFieldSpacegroup->SetValue(mpCrystal->GetSpaceGroup().GetName());
1780  #ifdef OBJCRYST_GL
1781  if(0!=mpCrystalGL) mpCrystalGL->GetParent()->SetLabel(wxString::Format("%s [%s]",mpCrystal->GetName().c_str(), mpCrystal->GetSpaceGroup().GetName().c_str()));
1782  #endif
1783  if(lock) mMutex.Unlock();
1784  }
1785  if(lock) mMutex.Lock();
1786  if(0!=mpScattPowWin)
1787  {
1788  map<ScatteringPowerAtom*,RowScattPow>::iterator pos;
1789  for(pos=mvpRowScattPow.begin();pos!=mvpRowScattPow.end();++pos)
1790  {
1791  if(pos->second.mNeedUpdateUI==true)
1792  {
1793  mIsSelfUpdating=true;
1794  mpScattPowWin->SetRowLabelValue(pos->second.mIdx, wxString::FromAscii(pos->second.mName.c_str()));
1795  wxString tmp;
1796  tmp.Printf(_T("%f"),pos->second.mBiso);
1797  mpScattPowWin->SetCellValue(pos->second.mIdx, 0, tmp);
1798  tmp.Printf(_T("%f"),pos->second.mFormalCharge);
1799  mpScattPowWin->SetCellValue(pos->second.mIdx, 1, tmp);
1800  tmp.Printf(_T("%f"),pos->second.mR);
1801  mpScattPowWin->SetCellValue(pos->second.mIdx, 2, tmp);
1802  tmp.Printf(_T("%f"),pos->second.mG);
1803  mpScattPowWin->SetCellValue(pos->second.mIdx, 3, tmp);
1804  tmp.Printf(_T("%f"),pos->second.mB);
1805  mpScattPowWin->SetCellValue(pos->second.mIdx, 4, tmp);
1806  tmp.Printf(_T("%f"),pos->second.mMaximumLikelihoodError);
1807  mpScattPowWin->SetCellValue(pos->second.mIdx, 5, tmp);
1808  tmp.Printf(_T("%f"),pos->second.mNbGhostAtoms);
1809  mpScattPowWin->SetCellValue(pos->second.mIdx, 6, tmp);
1810  mIsSelfUpdating=false;
1811  }
1812  }
1813  }
1814  if(0!=mpAntiBumpWin)
1815  {
1816  map<ScatteringPowerAtom*,RowScattPow>::iterator pos;
1817  for(pos=mvpRowScattPow.begin();pos!=mvpRowScattPow.end();++pos)
1818  {
1819  if(pos->second.mNeedUpdateUI==true)
1820  {
1821  mIsSelfUpdating=true;
1822  mpAntiBumpWin->SetRowLabelValue(pos->second.mIdx, wxString::FromAscii(pos->second.mName.c_str()));
1823  mpAntiBumpWin->SetColLabelValue(pos->second.mIdx, wxString::FromAscii(pos->second.mName.c_str()));
1824  wxString tmp;
1825  for(unsigned long j=0;j<pos->second.mvAntiBumpDistance.size();++j)
1826  {
1827  VFN_DEBUG_MESSAGE("WXCrystal::UpdateUI():Antibump("<<pos->first->GetName()
1828  <<",?"//<<mvScattPowRowIndex[j]->GetName()
1829  <<")="<<pos->second.mvAntiBumpDistance[j],3);
1830  if(pos->second.mvAntiBumpDistance[j]>-998)
1831  {
1832  tmp.Printf(_T("%f"),pos->second.mvAntiBumpDistance[j]);
1833  mpAntiBumpWin->SetCellValue(pos->second.mIdx,j,tmp);
1834  } else mpAntiBumpWin->SetCellValue(pos->second.mIdx,j,_T(""));
1835  }
1836  mIsSelfUpdating=false;
1837  }
1838  }
1839  }
1840  if(0!=mpBondValenceWin)
1841  {
1842  map<ScatteringPowerAtom*,RowScattPow>::iterator pos;
1843  for(pos=mvpRowScattPow.begin();pos!=mvpRowScattPow.end();++pos)
1844  {
1845  if(pos->second.mNeedUpdateUI==true)
1846  {
1847  mIsSelfUpdating=true;
1848  mpBondValenceWin->SetRowLabelValue(pos->second.mIdx, wxString::FromAscii(pos->second.mName.c_str()));
1849  mpBondValenceWin->SetColLabelValue(pos->second.mIdx, wxString::FromAscii(pos->second.mName.c_str()));
1850  wxString tmp;
1851  for(unsigned long j=0;j<pos->second.mvBondValenceRo.size();++j)
1852  {
1853  VFN_DEBUG_MESSAGE("WXCrystal::UpdateUI():BondValence("<<pos->first->GetName()
1854  <<",?"//<<mvScattPowRowIndex[j]->GetName()
1855  <<")="<<pos->second.mvBondValenceRo[j],3);
1856  if(pos->second.mvBondValenceRo[j]>-998)
1857  {
1858  tmp.Printf(_T("%f"),pos->second.mvBondValenceRo[j]);
1859  mpBondValenceWin->SetCellValue(pos->second.mIdx,j,tmp);
1860  } else mpBondValenceWin->SetCellValue(pos->second.mIdx,j,_T(""));
1861  }
1862  mIsSelfUpdating=false;
1863  }
1864  }
1865  }
1866  if(lock) mMutex.Unlock();
1867  this->WXRefinableObj::UpdateUI(lock);
1868  VFN_DEBUG_EXIT("WXCrystal::UpdateUI()",6)
1869 }
1870 Crystal& WXCrystal::GetCrystal(){return *mpCrystal;}
1871 const Crystal& WXCrystal::GetCrystal()const{return *mpCrystal;}
1872 
1873 void WXCrystal::OnMenuShowIntermoDistWindow(wxCommandEvent &event)
1874 {
1875  if(mpIntermolDistWin!=0) return;
1877  wxFrame *frame= new wxFrame(this,-1,_T("Intermolecular Distance Restraints"),
1878  wxDefaultPosition,wxSize(800,300));
1879 
1880  mpIntermolDistWin = new WXCrystalScrolledGridWindow(frame,this,ID_CRYSTAL_WIN_INTERMOLDIST_EVENT);
1881 
1882  //mpIntermolDistWin->SetDefaultRenderer(new wxGridCellFloatRenderer(5,3));
1883  //mpIntermolDistWin->SetDefaultEditor(new wxGridCellFloatEditor(5,3));
1884  mpIntermolDistWin->SetColMinimalAcceptableWidth(150);
1885  mpIntermolDistWin->CreateGrid(0,5);
1886 
1887  mpIntermolDistWin->SetColLabelValue(0,_T("At1"));
1888  mpIntermolDistWin->SetColLabelValue(1,_T("At2"));
1889  mpIntermolDistWin->SetColFormatFloat(2,5,3);
1890  mpIntermolDistWin->SetColLabelValue(2,_T("Distance"));
1891  mpIntermolDistWin->SetColFormatFloat(3,5,3);
1892  mpIntermolDistWin->SetColLabelValue(3,_T("Sigma"));
1893  mpIntermolDistWin->SetColFormatFloat(4,5,3);
1894  mpIntermolDistWin->SetColLabelValue(4,_T("Delta"));
1895 
1896  mpIntermolDistWin->AutoSizeRows();
1897  mpIntermolDistWin->AutoSizeColumns();
1898 
1899  mpIntermolDistWin->AppendRows(mpCrystal->GetIntermolDistNb());
1900  for(int i=0;i<mpCrystal->GetIntermolDistNb();i++) {
1901  Crystal::InterMolDistPar imdp = mpCrystal->GetIntermolDistPar(i);
1902  string tmpAt1;
1903  for(int j=0;j<imdp.mAt1.size();j++) {
1904  tmpAt1 += imdp.mAt1[j] + " ";
1905  }
1906  mpIntermolDistWin->SetCellValue(i, 0, tmpAt1);
1907 
1908  string tmpAt2;
1909  for(int j=0;j<imdp.mAt2.size();j++) {
1910  tmpAt2 += imdp.mAt2[j] + " ";
1911  }
1912  mpIntermolDistWin->SetCellValue(i, 1, tmpAt2);
1913  float d = imdp.mDist2;
1914  if(d>0.0) d=sqrt(d);
1915  mpIntermolDistWin->SetCellValue(i, 2, wxString::Format(wxT("%f"), d));
1916  mpIntermolDistWin->SetCellValue(i, 3, wxString::Format(wxT("%f"), imdp.mSig));
1917  mpIntermolDistWin->SetCellValue(i, 4, wxString::Format(wxT("%f"), imdp.mDelta));
1918  }
1919 
1920  this->CrystUpdate(true);
1921  frame->Show(true);
1922  frame->Layout();
1923  //mpCrystal->GetIntermolDistPar(0);
1924 }
1925 void WXCrystal::OnMenuShowScattPowWindow(wxCommandEvent &event)
1926 {
1927  VFN_DEBUG_MESSAGE("WXCrystal::OnMenuShowScattPowWindow()",10)
1928  if(0!=mpScattPowWin) return;
1929  WXCrystValidateAllUserInput();
1930  // Frame with notebook
1931  wxFrame *frame= new wxFrame(this,-1,_T("Scattering Powers parameters for: ")
1932  + wxString::FromAscii(this->GetCrystal().GetName().c_str()),
1933  wxDefaultPosition,wxSize(800,300));
1934 
1935  wxNotebook *notebook = new wxNotebook(frame, -1);
1936  {// Individual parameters
1937  mpScattPowWin = new WXCrystalScrolledGridWindow(notebook,this,ID_CRYSTAL_WIN_SCATTPOW);
1938  notebook->AddPage(mpScattPowWin, _T("Scattering Powers"), true);
1939 
1940  mpScattPowWin->SetDefaultRenderer(new wxGridCellFloatRenderer(5,3));
1941  mpScattPowWin->SetDefaultEditor(new wxGridCellFloatEditor(5,3));
1942  mpScattPowWin->SetColMinimalAcceptableWidth(150);
1943  mpScattPowWin->CreateGrid(0,7);
1944 
1945  mpScattPowWin->SetColLabelValue(0,_T("Biso"));
1946  mpScattPowWin->SetColLabelValue(1,_T("Charge"));
1947  mpScattPowWin->SetColLabelValue(2,_T("Red"));
1948  mpScattPowWin->SetColLabelValue(3,_T("Green"));
1949  mpScattPowWin->SetColLabelValue(4,_T("Blue"));
1950  mpScattPowWin->SetColLabelValue(5,_T("ML Error"));
1951  mpScattPowWin->SetColLabelValue(6,_T("#ghost"));
1952 
1953  mpScattPowWin->AutoSizeRows();
1954  mpScattPowWin->AutoSizeColumns();
1955  }
1956  {// Anti-Bump
1957  mpAntiBumpWin = new WXCrystalScrolledGridWindow(notebook,this,ID_CRYSTAL_WIN_ANTIBUMP);
1958  notebook->AddPage(mpAntiBumpWin, _T("AntiBump"), true);
1959 
1960  mpAntiBumpWin->SetDefaultRenderer(new wxGridCellFloatRenderer(5,3));
1961  mpAntiBumpWin->SetDefaultEditor(new wxGridCellFloatEditor(5,3));
1962  mpAntiBumpWin->SetColMinimalAcceptableWidth(150);
1963  mpAntiBumpWin->CreateGrid(0,0);
1964 
1965  mpAntiBumpWin->AutoSizeRows();
1966  mpAntiBumpWin->AutoSizeColumns();
1967  }
1968  {// Bond Valence
1969  mpBondValenceWin = new WXCrystalScrolledGridWindow(notebook,this,ID_CRYSTAL_WIN_BONDVALENCE);
1970  notebook->AddPage(mpBondValenceWin, _T("BondValence"), true);
1971 
1972  mpBondValenceWin->SetDefaultRenderer(new wxGridCellFloatRenderer(5,3));
1973  mpBondValenceWin->SetDefaultEditor(new wxGridCellFloatEditor(5,3));
1974  mpBondValenceWin->SetColMinimalAcceptableWidth(150);
1975  mpBondValenceWin->CreateGrid(0,0);
1976 
1977  mpBondValenceWin->AutoSizeRows();
1978  mpBondValenceWin->AutoSizeColumns();
1979  }
1980  notebook->SetSelection(0);
1981  this->CrystUpdate(true);
1982  frame->Show(true);
1983  frame->Layout();
1984 }
1985 void WXCrystal::OnEditGridIntermolDistWindow(wxGridEvent &e)
1986 {
1987  if(mIsSelfUpdating) return;
1988  if(mpCrystal->GetIntermolDistNb() == 0) return;
1989 
1990  const int r=e.GetRow();
1991  const int c=e.GetCol();
1992 
1993  Crystal::InterMolDistPar *imdp = mpCrystal->GetIntermolDistPar_ptr(r);
1994  if(imdp==0) return;
1995 
1996  wxString s=mpIntermolDistWin->GetCellValue(r,c);
1997 
1998  switch(c)
1999  {
2000  case 0:
2001  {//At1
2002  if(s!=_T(""))
2003  {
2004  stringstream ss(s.ToStdString());
2005  string word;
2006  vector<string> At1;
2007  while (ss >> word) {
2008  At1.push_back(word);
2009  }
2010  bool bad=false;
2011  for(int i=0;i<At1.size();i++) {
2012  if(mpCrystal->FindScatterersInComponentList(At1[i]).size()==0) {
2013  bad=true;
2014  wxMessageBox(wxString::Format("Atom with %s name does not exist !", At1[i].c_str()), _T("Unknown atom"), wxOK | wxICON_INFORMATION, this);
2015  break;
2016  }
2017  }
2018  if(!bad) {
2019  imdp->mAt1 = At1;
2020  }
2021  } else {
2022  wxMessageBox(_T("The cell is empty, please write there at least one atom name !"), _T("Unknown atom"), wxOK | wxICON_INFORMATION, this);
2023  }
2024  break;
2025  }
2026  case 1:
2027  {//At2
2028  if(s!=_T(""))
2029  {
2030  stringstream ss(s.ToStdString());
2031  string word;
2032  vector<string> At2;
2033  while (ss >> word) {
2034  At2.push_back(word);
2035  }
2036  bool bad=false;
2037  for(int i=0;i<At2.size();i++) {
2038  if(mpCrystal->FindScatterersInComponentList(At2[i]).size()==0) {
2039  bad=true;
2040  wxMessageBox(wxString::Format("Atom with %s name does not exist !", At2[i].c_str()), _T("Unknown atom"), wxOK | wxICON_INFORMATION, this);
2041  break;
2042  }
2043  }
2044  if(!bad) {
2045  imdp->mAt2 = At2;
2046  }
2047  } else {
2048  wxMessageBox(_T("The cell is empty, please write there at least one atom name !"), _T("Unknown atom"), wxOK | wxICON_INFORMATION, this);
2049  }
2050  break;
2051  }
2052  case 2:
2053  {//Distance
2054  if(s!=_T(""))
2055  {
2056  double d;
2057  s.ToDouble(&d);
2058  imdp->mDist2 = d*d;
2059  }
2060  break;
2061  }
2062  case 3:
2063  {//Sigma
2064  if(s!=_T(""))
2065  {
2066  double d;
2067  s.ToDouble(&d);
2068  imdp->mSig = d;
2069  }
2070  break;
2071  }
2072  case 4:
2073  {//Delta
2074  if(s!=_T(""))
2075  {
2076  double d;
2077  s.ToDouble(&d);
2078  imdp->mDelta = d;
2079  }
2080  break;
2081  }
2082  }
2083  mpCrystal->mInterMolDistListNeedsInit=true;
2084  this->CrystUpdate();
2085 
2086 }
2087 void WXCrystal::OnEditGridScattPow(wxGridEvent &e)
2088 {
2089  if(mIsSelfUpdating) return;
2090  const int r=e.GetRow();
2091  const int c=e.GetCol();
2092  map<ScatteringPowerAtom*,RowScattPow>::iterator pos=mvpRowScattPow.begin();
2093  while(pos->second.mIdx!=r)++pos;
2094  ScatteringPowerAtom *const p=pos->first;
2095 
2096  wxString s=mpScattPowWin->GetCellValue(r,c);
2097  switch(c)
2098  {
2099  case 0:
2100  {
2101  if(s!=_T(""))
2102  {
2103  double d;
2104  s.ToDouble(&d);
2105  p->SetBiso(d);
2106  }
2107  break;
2108  }
2109  case 1:
2110  {
2111  if(s!=_T(""))
2112  {
2113  double d;
2114  s.ToDouble(&d);
2115  p->SetFormalCharge(d);
2116  }
2117  break;
2118  }
2119  case 2:
2120  {
2121  if(s!=_T(""))
2122  {
2123  double d;
2124  s.ToDouble(&d);
2125  const REAL gg=p->GetColourRGB()[1];
2126  const REAL bb=p->GetColourRGB()[2];
2127  p->SetColour(d,gg,bb);
2128  }
2129  break;
2130  }
2131  case 3:
2132  {
2133  if(s!=_T(""))
2134  {
2135  double d;
2136  s.ToDouble(&d);
2137  const REAL rr=p->GetColourRGB()[0];
2138  const REAL bb=p->GetColourRGB()[2];
2139  p->SetColour(rr,d,bb);
2140  }
2141  break;
2142  }
2143  case 4:
2144  {
2145  if(s!=_T(""))
2146  {
2147  double d;
2148  s.ToDouble(&d);
2149  const REAL rr=p->GetColourRGB()[0];
2150  const REAL gg=p->GetColourRGB()[1];
2151  p->SetColour(rr,gg,d);
2152  }
2153  break;
2154  }
2155  case 5:
2156  {
2157  if(s!=_T(""))
2158  {
2159  double d;
2160  s.ToDouble(&d);
2161  p->SetMaximumLikelihoodPositionError(d);
2162  }
2163  break;
2164  }
2165  case 6:
2166  {
2167  if(s!=_T(""))
2168  {
2169  double d;
2170  s.ToDouble(&d);
2171  p->SetMaximumLikelihoodNbGhostAtom(d);
2172  }
2173  break;
2174  }
2175  }
2176  this->CrystUpdate();
2177 }
2178 
2179 void WXCrystal::OnEditGridScattPowAntiBump(wxGridEvent &e)
2180 {
2181  if(mIsSelfUpdating) return;
2182  const int r=e.GetRow();
2183  const int c=e.GetCol();
2184 
2185  map<ScatteringPowerAtom*,RowScattPow>::iterator pos=mvpRowScattPow.begin();
2186  while(pos->second.mIdx!=r)++pos;
2187  const ScatteringPowerAtom *const p1=pos->first;
2188 
2189  pos=mvpRowScattPow.begin();
2190  while(pos->second.mIdx!=c)++pos;
2191  const ScatteringPowerAtom *const p2=pos->first;
2192 
2193  wxString s=mpAntiBumpWin->GetCellValue(r,c);
2194  double d;
2195  s.ToDouble(&d);
2196  if(d>0.01) mpCrystal->SetBumpMergeDistance(*p1,*p2,d);
2197  else mpCrystal->RemoveBumpMergeDistance(*p1,*p2);
2198  this->CrystUpdate(true,false);
2199 }
2200 
2201 void WXCrystal::OnEditGridScattPowBondValence(wxGridEvent &e)
2202 {
2203  if(mIsSelfUpdating) return;
2204  const int r=e.GetRow();
2205  const int c=e.GetCol();
2206 
2207  map<ScatteringPowerAtom*,RowScattPow>::iterator pos=mvpRowScattPow.begin();
2208  while(pos->second.mIdx!=r)++pos;
2209  const ScatteringPowerAtom *const p1=pos->first;
2210 
2211  pos=mvpRowScattPow.begin();
2212  while(pos->second.mIdx!=c)++pos;
2213  const ScatteringPowerAtom *const p2=pos->first;
2214 
2215  wxString s=mpBondValenceWin->GetCellValue(r,c);
2216  double d;
2217  s.ToDouble(&d);
2218  if(d>0.01) mpCrystal->AddBondValenceRo(*p1,*p2,d);
2219  else mpCrystal->RemoveBondValenceRo(*p1,*p2);
2220  this->CrystUpdate(true,false);
2221 }
2222 
2223 void WXCrystal::NotifyDeleteListWin(WXCrystalScrolledGridWindow *win)
2224 {
2225  if(win==mpScattPowWin) mpScattPowWin=0;
2226  if(win==mpAntiBumpWin) mpAntiBumpWin=0;
2227  if(win==mpBondValenceWin) mpBondValenceWin=0;
2228  if(win==mpIntermolDistWin) mpIntermolDistWin=0;
2229  // NOTE : all three subwindows should actually be deleted at the *same* time.
2230  if((mpScattPowWin==0)&&(mpAntiBumpWin==0)&&(mpBondValenceWin==0)) mvpRowScattPow.clear();
2231 }
2232 
2233 /*
2234 void WXCrystal::OnMenuPDF(wxCommandEvent &event)
2235 {
2236  const unsigned int nb=1000;
2237  // Simulate data
2238  if(mpPDF!=0) delete mpPDF;
2239  mpPDF=new PDF();
2240  CrystVector_REAL r,obs;
2241  r.resize(nb);obs.resize(nb);
2242  for(unsigned int i=0;i<nb;++i) r(i)=(i+1)*.02;
2243  obs=1.0;
2244  mpPDF->SetPDFObs(r,obs);
2245  PDFCrystal *pPDFCrystal=new PDFCrystal(*mpPDF,*mpCrystal);
2246  mpPDF->AddPDFPhase(*pPDFCrystal);
2247  // WX window
2248  wxFrame *frame= new wxFrame(this,-1,"PDF",
2249  wxDefaultPosition,wxSize(300,200));
2250  WXMultiGraph* pGraph =new WXMultiGraph(frame);
2251 
2252  wxSizer *ps=new wxBoxSizer(wxHORIZONTAL);
2253  ps->Add(pGraph,1,wxEXPAND);
2254  frame->CreateStatusBar(2);
2255  frame->SetSizer(ps);
2256  frame->SetAutoLayout(true);
2257  frame->Show(true);
2258  unsigned long id=pGraph->AddGraph("PDF");
2259  valarray<float> vr(nb),vcalc(nb);
2260  CrystVector_REAL v2r,v2calc;
2261  v2r=mpPDF->GetPDFR();
2262  v2calc=mpPDF->GetPDFCalc();
2263  for(unsigned int i=0;i<nb;++i)
2264  {
2265  vr[i]=v2r(i);
2266  vcalc[i]=v2calc(i);
2267  }
2268  pGraph->SetGraphData(id,vr,vcalc);
2269  pGraph->UpdateDisplay();
2270 }
2271 */
2272 bool WXCrystal::Enable(bool e)
2273 {
2274  if(0!=mpScattPowWin) mpScattPowWin ->Enable(e);
2275  if(0!=mpAntiBumpWin) mpAntiBumpWin ->Enable(e);
2276  if(0!=mpBondValenceWin) mpBondValenceWin->Enable(e);
2277  if(0!=mpIntermolDistWin) mpIntermolDistWin->Enable(e);
2278  return this->::wxWindow::Enable(e);
2279 }
2280 
2281 #ifdef OBJCRYST_GL
2283 //
2284 // UnitCellMap
2285 //
2287 UnitCellMap::UnitCellMap(const Crystal&crystal):
2288 mpCrystal(&crystal)
2289 {}
2290 UnitCellMap::~UnitCellMap(){}
2291 void UnitCellMap::GLInitDisplayList(const float minValue,
2292  WXGLCrystalCanvas * parentCrystal) const
2293 {
2294  VFN_DEBUG_ENTRY("UnitCellMap::GLInitDisplayList()",10)
2295  //cout<<"Generating OpenGL Triangles for Fourier map:"<<mName<<", contour="<<minValue<<endl;
2296  // Generate triangles
2297  VFN_DEBUG_MESSAGE("UnitCellMap::GLInitDisplayList(): Generate Triangles",7)
2298 
2299  const int nx=mPoints.cols();
2300  const int ny=mPoints.rows();
2301  const int nz=mPoints.depth();
2302  float step[3];
2303  step[0]=1/(float)nx;
2304  step[1]=1/(float)ny;
2305  step[2]=1/(float)nz;
2306  int nxMin, nxMax, nyMin, nyMax, nzMin, nzMax;
2307  BBox mapbbox = parentCrystal->GetMapBBox();
2308  // use cell bbox if mapbbox has zero volume (default)
2309  if (mapbbox.xMin == mapbbox.xMax) mapbbox = parentCrystal->GetCellBBox();
2310  nxMin = (int)(mapbbox.xMin * nx);
2311  nxMax = (int)(mapbbox.xMax * nx);
2312  nyMin = (int)(mapbbox.yMin * ny);
2313  nyMax = (int)(mapbbox.yMax * ny);
2314  nzMin = (int)(mapbbox.zMin * nz);
2315  nzMax = (int)(mapbbox.zMax * nz);
2316  const int snx = nxMax-nxMin+1, sny = nyMax-nyMin+1, snz = nzMax-nzMin+1;
2317  const unsigned int sny_snz = sny*snz;
2318  int i, j, k;
2319  unsigned int ni, nj, si, sj, sk, sni, snj, sind;
2320  REAL x, y, z;
2321 
2322  //create new set of points
2323  mp4Vector * subPoints = new mp4Vector[snx*sny*snz];
2324  for(i=nxMin, si=0; i <= nxMax; i++, si++)
2325  {
2326  ni = ((nx + i % nx) % nx); //this will 'wrap' around any value (negative or positive)
2327  sni = si*sny_snz;
2328  for(j=nyMin, sj=0; j <= nyMax; j++, sj++)
2329  {
2330  nj = ((ny + j % ny) % ny);
2331  snj = sj*snz;
2332  for(k=nzMin, sk=0; k <= nzMax; k++, sk++)
2333  {
2334  sind = sni + snj + sk;
2335  x = i*step[0]; y = j*step[1]; z = k*step[2];
2336  mpCrystal->FractionalToOrthonormalCoords(x, y, z);
2337  subPoints[sind].x = x; subPoints[sind].y = y; subPoints[sind].z = z;
2338  //cout << ni <<" "<<nj<<" "<<(nz+ k % nz)<<endl;
2339  subPoints[sind].val = mPoints((nz+ k % nz)% nz,nj,ni);
2340  }
2341  }
2342  }
2343  int numOfTriangles;
2344  VFN_DEBUG_MESSAGE("UnitCellMap::GLInitDisplayList(): MC, Min Value="<<minValue,10)
2345  const TRIANGLE *pTriangles= MC(snx-1, sny-1, snz-1, step[0], step[1], step[2], minValue, subPoints, numOfTriangles);
2346  // OpenGL drawing instructions
2347  VFN_DEBUG_MESSAGE("UnitCellMap::GLInitDisplayList(): OpenGL instructions",7)
2348  glBegin(GL_TRIANGLES);
2349  float normx,normy,normz;
2350  for(int i=0; i < numOfTriangles; i++)
2351  {
2352  if(minValue>0)
2353  for(int j=0; j < 3; j++)
2354  {
2355  //VFN_DEBUG_MESSAGE("WXGLCrystalCanvas::OnPaint():MC1:"<<i<<" "<<j,5)
2356  //:TODO: Fix normals
2357  normx=pTriangles[i].norm[j].x;
2358  normy=pTriangles[i].norm[j].y;
2359  normz=pTriangles[i].norm[j].z;
2360  //mpCrystal->FractionalToOrthonormalCoords(normx, normy, normz);
2361  //mpCrystal->OrthonormalToFractionalCoords(normx, normy, normz);
2362  glNormal3f(normx, normy, normz);
2363  glVertex3f(pTriangles[i].p[j].x ,pTriangles[i].p[j].y ,pTriangles[i].p[j].z);
2364  }
2365  else
2366  for(int j=2; j >=0; j--)
2367  {
2368  //VFN_DEBUG_MESSAGE("WXGLCrystalCanvas::OnPaint():MC1:"<<i<<" "<<j,5)
2369  //:TODO: Fix normals
2370  normx=-pTriangles[i].norm[j].x;
2371  normy=-pTriangles[i].norm[j].y;
2372  normz=-pTriangles[i].norm[j].z;
2373  //mpCrystal->FractionalToOrthonormalCoords(normx, normy, normz);
2374  //mpCrystal->OrthonormalToFractionalCoords(normx, normy, normz);
2375  glNormal3f(normx, normy, normz);
2376  glVertex3f(pTriangles[i].p[j].x ,pTriangles[i].p[j].y ,pTriangles[i].p[j].z);
2377  }
2378  }
2379  glEnd();
2380 
2381  delete [] subPoints;
2382  delete [] pTriangles;
2383  VFN_DEBUG_EXIT("UnitCellMap::GLInitDisplayList():nb triangles="<<numOfTriangles,10)
2384 }
2385 
2386 void UnitCellMap::POVRayDescription(ostream &os,const float minValue,
2387  const CrystalPOVRayOptions &options)const
2388 {// basically the same code asGLInitDisplayList(), but creates cylinders
2389  VFN_DEBUG_ENTRY("UnitCellMap::POVRayDescription()",7)
2390  // Generate triangles
2391  VFN_DEBUG_MESSAGE("UnitCellMap::POVRayDescription(): Generate Triangles",7)
2392 
2393  const int nx=mPoints.cols();
2394  const int ny=mPoints.rows();
2395  const int nz=mPoints.depth();
2396  float step[3];
2397  step[0]=1/(float)nx;
2398  step[1]=1/(float)ny;
2399  step[2]=1/(float)nz;
2400  int nxMin, nxMax, nyMin, nyMax, nzMin, nzMax;
2401  nxMin = (int)(options.mXmin * nx);
2402  nxMax = (int)(options.mXmax * nx);
2403  nyMin = (int)(options.mYmin * ny);
2404  nyMax = (int)(options.mYmax * ny);
2405  nzMin = (int)(options.mZmin * nz);
2406  nzMax = (int)(options.mZmax * nz);
2407  const int snx = nxMax-nxMin+1, sny = nyMax-nyMin+1, snz = nzMax-nzMin+1;
2408  const unsigned int sny_snz = sny*snz;
2409  int i, j, k;
2410  unsigned int ni, nj, si, sj, sk, sni, snj, sind;
2411  REAL x, y, z;
2412 
2413  //create new set of points
2414  mp4Vector * subPoints = new mp4Vector[snx*sny*snz];
2415  for(i=nxMin, si=0; i <= nxMax; i++, si++)
2416  {
2417  ni = ((nx + i % nx) % nx); //this will 'wrap' around any value (negative or positive)
2418  sni = si*sny_snz;
2419  for(j=nyMin, sj=0; j <= nyMax; j++, sj++)
2420  {
2421  nj = ((ny + j % ny) % ny);
2422  snj = sj*snz;
2423  for(k=nzMin, sk=0; k <= nzMax; k++, sk++)
2424  {
2425  sind = sni + snj + sk;
2426  x = i*step[0]; y = j*step[1]; z = k*step[2];
2427  mpCrystal->FractionalToOrthonormalCoords(x, y, z);
2428  subPoints[sind].x = x; subPoints[sind].y = y; subPoints[sind].z = z;
2429  //cout << ni <<" "<<nj<<" "<<(nz+ k % nz)<<endl;
2430  subPoints[sind].val = mPoints((nz+ k % nz)% nz,nj,ni);
2431  }
2432  }
2433  }
2434  int numOfTriangles;
2435  VFN_DEBUG_MESSAGE("UnitCellMap::POVRayDescription(): MC, Min Value="<<minValue,10)
2436  const TRIANGLE *pTriangles= MC(snx-1, sny-1, snz-1, step[0], step[1], step[2], minValue, subPoints, numOfTriangles);
2437  // drawing instructions
2438  VFN_DEBUG_MESSAGE("UnitCellMap::POVRayDescription(): POVRay instructions",7)
2439  float normx,normy,normz;
2440  for(int i=0; i < numOfTriangles; i++)
2441  {
2442  const float x1=pTriangles[i].p[0].x;
2443  const float x2=pTriangles[i].p[1].x;
2444  const float x3=pTriangles[i].p[2].x;
2445  const float y1=pTriangles[i].p[0].y;
2446  const float y2=pTriangles[i].p[1].y;
2447  const float y3=pTriangles[i].p[2].y;
2448  const float z1=pTriangles[i].p[0].z;
2449  const float z2=pTriangles[i].p[1].z;
2450  const float z3=pTriangles[i].p[2].z;
2451 
2452  // Avoid null-length cylinders that make POV-Ray choke
2453  const float d12=abs(x1-x2)+abs(y1-y2)+abs(z1-z2);
2454  const float d13=abs(x1-x3)+abs(y1-y3)+abs(z1-z3);
2455  const float d23=abs(x2-x3)+abs(y2-y3)+abs(z2-z3);
2456  if((d12<0.05)||(d13<0.05)||(d23<0.05)) continue;
2457 
2458  //:TODO: Fix normals
2459  normx=pTriangles[i].norm[j].x;
2460  normy=pTriangles[i].norm[j].y;
2461  normz=pTriangles[i].norm[j].z;
2462  //mpCrystal->FractionalToOrthonormalCoords(normx, normy, normz);
2463  //mpCrystal->OrthonormalToFractionalCoords(normx, normy, normz);
2464  os<<" ObjCrystMeshTriangle("
2465  <<x1<<","<<y1<<","<<z1<<","
2466  <<x2<<","<<y2<<","<<z2<<","
2467  <<x3<<","<<y3<<","<<z3<<","
2468  <<normx<<","<<normy<<","<<normz<<","
2469  <<normx<<","<<normy<<","<<normz<<","
2470  <<normx<<","<<normy<<","<<normz<<")"
2471  <<endl;
2472  }
2473 
2474  delete [] subPoints;
2475  delete [] pTriangles;
2476  VFN_DEBUG_EXIT("UnitCellMap::GLInitDisplayList()",7)
2477 }
2478 
2479 int UnitCellMap::ImportGRD(const string&filename)
2480 {
2481  VFN_DEBUG_ENTRY("UnitCellMap::ImportGRD()",7)
2482  ifstream ffile(filename.c_str());
2483  if(!ffile.is_open())
2484  { //if file could not be loaded for some reason then exit
2485  VFN_DEBUG_MESSAGE("UnitCellMap::ImportGRD() error opening "<<filename.c_str(),10)
2486  (*fpObjCrystInformUser)("Error opening file: "+filename);
2487  return 0;
2488  }
2489  //message for reporting errors
2490  char buff[99];
2491  ffile.getline(buff, 100);
2492  float a, b, c, alpha, beta, gamma;
2493  ffile >>a >>b >>c >>alpha >>beta >>gamma;
2494  if(!ffile.good()) { (*fpObjCrystInformUser)("Error reading file: "+filename); return 0; }
2495  //compare dimensions with the original crystal and notify the user if not equal
2496  /*
2497  float afac = 180/M_PI, limit = 0.0001;
2498  if((a - mpWXCrystal->GetCrystal().GetLatticePar()(0)) > limit || (b - mpWXCrystal->GetCrystal().GetLatticePar()(1))> limit ||
2499  (c - mpWXCrystal->GetCrystal().GetLatticePar()(2)) > limit || (alpha - mpWXCrystal->GetCrystal().GetLatticePar()(3)*afac) > limit ||
2500  (beta - mpWXCrystal->GetCrystal().GetLatticePar()(4)*afac) > limit || (gamma - mpWXCrystal->GetCrystal().GetLatticePar()(5)*afac) > limit )
2501  if(wxMessageBox(wxString::Format("Cell dimensions in the file do not match those of the crystal loaded:\n\n" +
2502  wxString("These are the value:\n") + " Crystal: File:\n a = %f a = %f\n"
2503  " b = %f b = %f\n c = %f c = %f\n alpha = %f alpha = %f\n" +
2504  " beta = %f beta = %f\n gamma = %f gamma = %f\n\nPercent errors are:\n" +
2505  " a: %f\n b: %f\n c: %f\n alpha: %f\n beta: %f\n gamma: %f\n\n\n"+
2506  "Continue loading " + filename.c_str() + " ?",
2507  mpWXCrystal->GetCrystal().GetLatticePar()(0), a, mpWXCrystal->GetCrystal().GetLatticePar()(1), b,
2508  mpWXCrystal->GetCrystal().GetLatticePar()(2), c, mpWXCrystal->GetCrystal().GetLatticePar()(3)*afac, alpha,
2509  mpWXCrystal->GetCrystal().GetLatticePar()(4)*afac, beta,mpWXCrystal->GetCrystal().GetLatticePar()(5)*afac, gamma,
2510  fabs(a-mpWXCrystal->GetCrystal().GetLatticePar()(0)) / mpWXCrystal->GetCrystal().GetLatticePar()(0)*100,
2511  fabs(b-mpWXCrystal->GetCrystal().GetLatticePar()(1)) / mpWXCrystal->GetCrystal().GetLatticePar()(1)*100,
2512  fabs(c-mpWXCrystal->GetCrystal().GetLatticePar()(2)) / mpWXCrystal->GetCrystal().GetLatticePar()(2)*100,
2513  fabs(alpha-mpWXCrystal->GetCrystal().GetLatticePar()(3)*afac) / mpWXCrystal->GetCrystal().GetLatticePar()(3)*afac*100,
2514  fabs(beta-mpWXCrystal->GetCrystal().GetLatticePar()(4)*afac ) / mpWXCrystal->GetCrystal().GetLatticePar()(4)*afac*100,
2515  fabs(gamma-mpWXCrystal->GetCrystal().GetLatticePar()(5)*afac) / mpWXCrystal->GetCrystal().GetLatticePar()(5)*afac*100 ),
2516  "Cell Dimensions Notice", wxYES_NO | wxCENTRE, (wxWindow*)this) == wxNO)
2517  {
2518  ffile.close();
2519  return;
2520  }
2521  */
2522  int nx,ny,nz;
2523  ffile >>nx >>ny >>nz;
2524  if(!ffile.good()) { (*fpObjCrystInformUser)("Error reading file: "+filename); return 0; }
2525  mPoints.resize(nz,ny,nx);
2526  for(int i=0; i < nx; i++) {
2527  for(int j=0; j < ny; j++) {
2528  for(int k=0; k < nz; k++) {
2529  ffile >>mPoints(k,j,i); //reading rhos
2530  }
2531  }
2532  }
2533  ffile.close();
2534 
2535  mMean=mPoints.sum()/(REAL)(mPoints.numElements());
2536  mMin=mPoints.min();
2537  mMax=mPoints.max();
2538  {
2539  mStandardDeviation=0.0;
2540  const REAL *tmp=mPoints.data();
2541  for(long i=0;i<mPoints.numElements();i++)
2542  {
2543  mStandardDeviation += (*tmp-mMean) * (*tmp-mMean);
2544  tmp++;
2545  }
2546  mStandardDeviation = sqrt(mStandardDeviation/(REAL)(mPoints.numElements()));
2547  }
2548  /*
2549  cout << "Min density value="<<mMin<<endl
2550  << "Max density value="<<mMax<<endl
2551  << "Mean density="<<mMean<<endl
2552  << "Standard Deviation="<<mStandardDeviation<<endl;
2553  */
2554  {// Use short name
2555  std::string::size_type idx =filename.rfind("/");
2556  std::string::size_type idx2=filename.rfind("\\");
2557  std::string::size_type idx3=filename.rfind(":");
2558  if(((long)idx2!=(long)string::npos)&&((long)idx2>(long)idx))idx=idx2;
2559  if(((long)idx3!=(long)string::npos)&&((long)idx3>(long)idx))idx=idx3;
2560  if(idx==string::npos)
2561  mName=filename;
2562  else
2563  {
2564  cout<<"name="<<filename.substr(idx+1)<<endl;
2565  mName=filename.substr(idx+1);
2566  }
2567  }
2568  mType=3;
2569  VFN_DEBUG_EXIT("UnitCellMap::ImportGRD()",7)
2570  return 1;
2571 }
2572 
2574 void swap2(void *data, unsigned int nb)
2575 {
2576  char * dataptr = (char *)data;
2577  char tmp;
2578 
2579  for (unsigned int i=0; i<(nb-1); i+=2)
2580  {
2581  tmp = dataptr[i];
2582  dataptr[i] = dataptr[i+1];
2583  dataptr[i+1] = tmp;
2584  }
2585 }
2586 
2587 int UnitCellMap::ImportDSN6(const string&filename)
2588 {
2589  VFN_DEBUG_ENTRY("UnitCellMap::ImportDSN6()",7)
2590  FILE *pfile=fopen(filename.c_str(),"rb");
2591  if(NULL==pfile)
2592  { //if file could not be loaded for some reason then exit
2593  VFN_DEBUG_MESSAGE("UnitCellMap::ImportDSN6() error opening "<<filename.c_str(),10)
2594  (*fpObjCrystInformUser)("Error opening file: "+filename);
2595  return 0;
2596  }
2597  // :KLUDGE: assume sizeof(short int)==2...
2598  short header[256];
2599  fread(header, sizeof(short), 256, pfile);
2600  bool needswap=false;
2601  if (header[18] == 25600) needswap=true;
2602  if(needswap) swap2(header, 19*sizeof(short));
2603 
2604  const long xstart=header[0];
2605  const long ystart=header[1];
2606  const long zstart=header[2];
2607  const long xextent=header[3];
2608  const long yextent=header[4];
2609  const long zextent=header[5];
2610  const unsigned long xsamplingrate=header[6];
2611  const unsigned long ysamplingrate=header[7];
2612  const unsigned long zsamplingrate=header[8];
2613  const float celledgea=(float)header[ 9]/(float)header[17];
2614  const float celledgeb=(float)header[10]/(float)header[17];
2615  const float celledgec=(float)header[11]/(float)header[17];
2616  const float alpha=(float)header[12]/(float)header[17];
2617  const float beta=(float)header[13]/(float)header[17];
2618  const float gamma=(float)header[14]/(float)header[17];
2619  const float rhoscale=(float)header[15]/(float)header[18];
2620  const float rhozero =(float)header[16];
2621  cout <<"xstart="<<xstart<<endl
2622  <<"ystart="<<ystart<<endl
2623  <<"zstart="<<zstart<<endl
2624  <<"xextent="<<xextent<<endl
2625  <<"yextent="<<yextent<<endl
2626  <<"zextent="<<zextent<<endl
2627  <<"xsamplingrate="<<xsamplingrate<<endl
2628  <<"ysamplingrate="<<ysamplingrate<<endl
2629  <<"zsamplingrate="<<zsamplingrate<<endl
2630  <<"celledgea="<<celledgea<<endl
2631  <<"celledgeb="<<celledgeb<<endl
2632  <<"celledgec="<<celledgec<<endl
2633  <<"alpha="<<alpha<<endl
2634  <<"beta="<<beta<<endl
2635  <<"gamma="<<gamma<<endl
2636  <<"rhoscale="<<rhoscale<<endl
2637  <<"rhozero="<<rhozero<<endl;
2638 
2639  #define BRICKSIZE 512
2640  #define BRICKEDGE 8
2641 
2642  unsigned char Points[BRICKSIZE];
2643  // :KLUDGE: stored map is the size of the entire unit cell, not of the input map...
2644  // The result is that if the input map is smaller than the unit cell size,
2645  // the rest of the cell will be with zero density
2646  mPoints.resize(xsamplingrate,ysamplingrate,zsamplingrate);
2647  mPoints=0;
2648 
2649  const unsigned int nxbrick=((xextent)/BRICKEDGE)+(xextent%8 ? 1 : 0);
2650  const unsigned int nybrick=((yextent)/BRICKEDGE)+(zextent%8 ? 1 : 0);
2651  const unsigned int nzbrick=((zextent)/BRICKEDGE)+(zextent%8 ? 1 : 0);
2652 
2653  for(unsigned int zbrick=0;zbrick<nzbrick;zbrick++)
2654  for(unsigned int ybrick=0;ybrick<nybrick;ybrick++)
2655  for(unsigned int xbrick=0;xbrick<nxbrick;xbrick++)
2656  {
2657  fread(&Points, sizeof(unsigned char), BRICKSIZE, pfile);
2658  // In this SICK format, data is stored as bytes, but which are
2659  // nevertheless byteswapped as 2-byte words. Bizarre, vous avez dit bizarre...
2660  if(needswap) swap2((void *)&Points, BRICKSIZE);
2661  const unsigned char* pPoint=&Points[0];
2662  for(unsigned int z=0;z<BRICKEDGE;z++)
2663  for(unsigned int y=0;y<BRICKEDGE;y++)
2664  for(unsigned int x=0;x<BRICKEDGE;x++)
2665  {
2666  if( ((xbrick*BRICKEDGE+x)<xsamplingrate)
2667  &&((ybrick*BRICKEDGE+y)<ysamplingrate)
2668  &&((zbrick*BRICKEDGE+z)<zsamplingrate))
2669  mPoints(zbrick*BRICKEDGE+z,ybrick*BRICKEDGE+y,xbrick*BRICKEDGE+x)
2670  = ((float) *pPoint - rhozero)/ rhoscale ;
2671  pPoint++;
2672  }
2673  }
2674  fclose (pfile);
2675 
2676  mMean=mPoints.sum()/(REAL)(mPoints.numElements());
2677  mMin=mPoints.min();
2678  mMax=mPoints.max();
2679  {
2680  mStandardDeviation=0.0;
2681  const REAL *tmp=mPoints.data();
2682  for(long i=0;i<mPoints.numElements();i++)
2683  {
2684  mStandardDeviation += (*tmp-mMean) * (*tmp-mMean);
2685  tmp++;
2686  }
2687  mStandardDeviation = sqrt(mStandardDeviation/(REAL)(mPoints.numElements()));
2688  }
2689  /*
2690  cout << "Min density value="<<mMin<<endl
2691  << "Max density value="<<mMax<<endl
2692  << "Mean density="<<mMean<<endl
2693  << "Standard Deviation="<<mStandardDeviation<<endl;
2694  */
2695  {// Use short name
2696  std::string::size_type idx =filename.rfind("/");
2697  std::string::size_type idx2=filename.rfind("\\");
2698  std::string::size_type idx3=filename.rfind(":");
2699  if(((long)idx2!=(long)string::npos)&&((long)idx2>(long)idx))idx=idx2;
2700  if(((long)idx3!=(long)string::npos)&&((long)idx3>(long)idx))idx=idx3;
2701  if(idx==string::npos)
2702  mName=filename;
2703  else
2704  {
2705  //cout<<"name="<<filename.substr(idx+1)<<endl;
2706  mName=filename.substr(idx+1);
2707  }
2708  }
2709  VFN_DEBUG_EXIT("UnitCellMap::ImportDSN6()",7)
2710  mType=3;
2711  return 1;
2712 }
2713 #ifdef HAVE_FFTW
2714 
2719 unsigned int closest235(unsigned int v)
2720 {// This is not particularly fast but we need few iterations so...
2721  unsigned int n2=0,n3=0,n5=0;
2722  unsigned int v2,v3,v5=1;
2723  unsigned int bestdiff=10000;
2724  unsigned int best=0;
2725  for(unsigned int i5=1;;)
2726  {
2727  v3=1;
2728  for(unsigned int i3=1;;)
2729  {
2730  v2=1;
2731  for(unsigned int i2=1;;)
2732  {
2733  const unsigned int n=v2*v3*v5;
2734  if(n>v)
2735  {
2736  if((n-v)<bestdiff)
2737  {
2738  bestdiff=n-v;
2739  n2=i2;
2740  n3=i3;
2741  n5=i5;
2742  best=n;
2743  if(best==v) return best;
2744  }
2745  else break;
2746  }
2747  v2*=2;i2+=1;
2748  }
2749  v3*=3;i3+=1;
2750  if((v3*v5)>(v+bestdiff)) break;
2751  }
2752  v5*=5;i5+=1;
2753  if(v5>(v+bestdiff)) break;
2754  }
2755  return best;
2756 }
2757 
2758 int UnitCellMap::CalcFourierMap(const ScatteringData& data, unsigned int type0, const bool normalized_sf)
2759 {
2760  mpData=&data;
2761  const float resolution=0.3;//Approximate resolution in Ansgtroem
2762  // We need something like 2^n2 * 3^n3 * 5^n5 - just use a power of 2 now
2763  const unsigned long sizex=closest235((unsigned int)floor(mpCrystal->GetLatticePar(0)/resolution+.5)) ;//int(pow((double)2, (double)ceil(log(mpCrystal->GetLatticePar(0)/resolution)/log(2)))+.00001);
2764  const unsigned long sizey=closest235((unsigned int)floor(mpCrystal->GetLatticePar(1)/resolution+.5)) ;//int(pow((double)2, (double)ceil(log(mpCrystal->GetLatticePar(1)/resolution)/log(2)))+.00001);
2765  const unsigned long sizez=closest235((unsigned int)floor(mpCrystal->GetLatticePar(2)/resolution+.5)) ;//int(pow((double)2, (double)ceil(log(mpCrystal->GetLatticePar(2)/resolution)/log(2)))+.00001);
2766  //cout<<"UnitCellMap::CalcFourierMap():"<<sizex<<","<<sizey<<","<<sizez<<","<<endl;
2767  fftwf_complex *in= (fftwf_complex*) fftwf_malloc(sizeof(fftwf_complex) * sizex*sizey*sizez);
2768  fftwf_plan plan=fftwf_plan_dft_3d(sizez, sizey, sizex,in, in,FFTW_FORWARD, FFTW_ESTIMATE);
2769 
2770  float *p=(float*)in;
2771  for(unsigned long i=0;i<sizex*sizey*sizez*2;i++) *p++=0;
2772 
2773  const long nb=data.GetNbReflBelowMaxSinThetaOvLambda();
2774 
2775  mType=type0;
2776  if(data.GetFhklObsSq().numElements()==0) mType=1;
2777 
2778  CrystVector_REAL norm_sf;
2779  if(normalized_sf)
2780  {
2781  CrystVector_REAL tmp;
2782  norm_sf.resize(data.GetFhklCalcReal().numElements());
2783  norm_sf=0;
2784  const map<const ScatteringPower*,CrystVector_REAL> *pSF=&(data.GetScatteringFactor());
2785  const ScatteringComponentList *pComp =&(mpCrystal->GetScatteringComponentList());
2786  REAL norm0=0;// norm_sf normalized to 1 at low angle
2787  for(unsigned int i=0;i<pComp->GetNbComponent();i++)
2788  {
2789  tmp=pSF->find((*pComp)(i).mpScattPow)->second;// safe enough ?
2790  tmp*=tmp;
2791  tmp*= (*pComp)(i).mOccupancy * (*pComp)(i).mDynPopCorr;
2792 
2793  const REAL sf0=(*pComp)(i).mpScattPow->GetForwardScatteringFactor(data.GetRadiationType ());
2794  norm0+=(*pComp)(i).mOccupancy * (*pComp)(i).mDynPopCorr *sf0*sf0;
2795 
2796  norm_sf+=tmp;
2797  }
2798  REAL *p=norm_sf.data();
2799  norm0=1/norm0;
2800  for(unsigned int i=norm_sf.numElements();i>0;i--) {*p=sqrt(*p * norm0);p++;}
2801  }
2802 
2803  // Auto-scale Fcalc and Fobs ?
2804  REAL scale_fobs=1.0;
2805  if(mType!=1)
2806  {
2807  REAL tmp=0;
2808  scale_fobs=0;
2809  for(long i=0;i<nb;++i) {scale_fobs+=data.GetFhklCalcSq()(i); tmp+=data.GetFhklObsSq()(i);}
2810  scale_fobs=sqrt(scale_fobs/(tmp+1e-10));
2811  //cout<<__FILE__<<":"<<__LINE__<<" Fourier map obs/calc scale factor:"<<scale_fobs<<endl;
2812  }
2813 
2814  const REAL v=1/mpCrystal->GetVolume();//(REAL)(size*size*size);// mpCrystal->GetVolume(); (REAL)(size*size*size);
2815  for(long i=0;i<nb;++i)
2816  {
2817  CrystMatrix_REAL m=mpCrystal->GetSpaceGroup().GetAllEquivRefl (data.GetH()(i),data.GetK()(i),data.GetL()(i),
2818  false, data.IsIgnoringImagScattFact(),
2819  data.GetFhklCalcReal()(i),data.GetFhklCalcImag()(i));
2820  REAL norm=1.0;
2821  if(normalized_sf) norm=1/norm_sf(i);
2822  for(int j=0;j<m.rows();j++)
2823  {
2824  int h=int(m(j,0)),k=int(m(j,1)),l=int(m(j,2));
2825  if((abs(h*2)>sizex)||(abs(k*2)>sizey)||(abs(l*2)>sizez)) continue;
2826  h=(h+sizex)%sizex;// e.g. h=-1 is at nx-1
2827  k=(k+sizey)%sizey;
2828  l=(l+sizez)%sizez;
2829  /*
2830  cout <<int(m(j,0))<<" "<<int(m(j,1))<<" "<<int(m(j,2))<<"("
2831  <<mpCrystal->GetSpaceGroup().IsReflCentric(data.GetH()(i),data.GetK()(i),data.GetL()(i))<<"):"
2832  <<m(j,3)<<"+"<<m(j,4)<<"i"<<endl;
2833  */
2834  if(mType==2)
2835  {// Obs-Calc
2836  const REAL fobs=scale_fobs*sqrt(fabs(data.GetFhklObsSq()(i)));
2837  const REAL rec=m(j,3),imc=m(j,4),fcalc=sqrt(fabs(data.GetFhklCalcSq()(i)));
2838  in[h+sizex*k+sizex*sizey*l][0]=v*rec*(fobs-fcalc)/sqrt(rec*rec+imc*imc)*norm;
2839  in[h+sizex*k+sizex*sizey*l][1]=v*imc*(fobs-fcalc)/sqrt(rec*rec+imc*imc)*norm;
2840  }
2841  if(mType==1)
2842  {// Calc
2843  in[h+sizex*k+sizex*sizey*l][0]=v*m(j,3)*norm;
2844  in[h+sizex*k+sizex*sizey*l][1]=v*m(j,4)*norm;
2845  }
2846  if(mType==0)
2847  {// Obs
2848  const REAL iobs=scale_fobs*sqrt(fabs(data.GetFhklObsSq()(i)));
2849  const REAL rec=m(j,3),imc=m(j,4),icalc=sqrt(fabs(data.GetFhklCalcSq()(i)));
2850  in[h+sizex*k+sizex*sizey*l][0]=v*rec*iobs/icalc*norm;
2851  in[h+sizex*k+sizex*sizey*l][1]=v*imc*iobs/icalc*norm;
2852  }
2853  }
2854  //cout<<endl;
2855  }
2856 
2857  if(mType!=2)
2858  {// F000, for obs & calc fourier maps ?
2859  const int nbSymmetrics=mpCrystal->GetSpaceGroup().GetNbSymmetrics(false,false);
2860  const ScatteringComponentList *pScattCompList=&(mpCrystal->GetScatteringComponentList());
2861  const long nbComp=pScattCompList->GetNbComponent();
2862  for(long i=0;i<nbComp;i++)
2863  {
2864  //TODO: include f" en forward scattering factor ?
2865  in[0][0]+= (*pScattCompList)(i).mpScattPow->GetForwardScatteringFactor(data.GetRadiationType())
2866  *(*pScattCompList)(i).mOccupancy
2867  *(*pScattCompList)(i).mDynPopCorr
2868  *nbSymmetrics*v;
2869  }
2870  //cout<<"F(000)="<<in[0][0]/v<<endl;
2871  }
2872  fftwf_execute(plan);
2873  mPoints.resize(sizez,sizey,sizex);
2874  REAL *p1=mPoints.data();
2875  for(unsigned int i=0;i<sizex*sizey*sizez;i++) *p1++ =in[i][0] ;
2876  /*
2877  for(unsigned int ix=0;ix<sizex;ix++)
2878  for(unsigned int iy=0;iy<sizey;iy++)
2879  for(unsigned int iz=0;iz<sizez;iz++)
2880  mPoints(iz,iy,ix)=in[ix+sizex*iy+sizex*sizey*iz][0];
2881  */
2882  mMean=mPoints.sum()/(REAL)(mPoints.numElements());
2883  mMin=mPoints.min();
2884  mMax=mPoints.max();
2885  {
2886  mStandardDeviation=0.0;
2887  const REAL *tmp=mPoints.data();
2888  for(long i=0;i<mPoints.numElements();i++)
2889  {
2890  mStandardDeviation += (*tmp-mMean) * (*tmp-mMean);
2891  tmp++;
2892  }
2893  mStandardDeviation = sqrt(mStandardDeviation/(REAL)(mPoints.numElements()));
2894  }
2895  /*
2896  cout << "Min density value="<<mMin<<endl
2897  << "Max density value="<<mMax<<endl
2898  << "Mean density="<<mMean<<endl
2899  << "Standard Deviation="<<mStandardDeviation<<endl;
2900  */
2901  fftwf_destroy_plan(plan);
2902  fftwf_free(in);
2903 
2904  mName=data.GetClassName()+":";
2905  if(data.GetName()=="") mName+="?";
2906  else mName+=data.GetName();
2907  if(data.GetClassName()=="PowderPatternDiffraction")
2908  {
2909  mName="P:";
2910  if(data.GetRadiationType()==RAD_XRAY) mName+="Xray:";
2911  if(data.GetRadiationType()==RAD_NEUTRON) mName+="Neut:";
2912  if(data.GetRadiationType()==RAD_ELECTRON) mName+="Elec:";
2913 
2914  char buf[100];
2915  if(data.GetRadiation().GetWavelengthType()==WAVELENGTH_TOF) mName+="TOF:";
2916  else
2917  {
2918  sprintf(buf,"%6.3fA:",data.GetWavelength()(0));
2919  mName+=buf;
2920  }
2921  const PowderPatternDiffraction* diff=dynamic_cast<const PowderPatternDiffraction *>(&data);
2922  if(diff!=0) mName+=diff->GetParentPowderPattern().GetName();
2923  }
2924  if(data.GetClassName()=="DiffractionDataSingleCrystal")
2925  {
2926  mName="S:";
2927  if(data.GetRadiationType()==RAD_XRAY) mName+="Xray:";
2928  if(data.GetRadiationType()==RAD_NEUTRON) mName+="Neut:";
2929  if(data.GetRadiationType()==RAD_ELECTRON) mName+="Elec:";
2930 
2931  char buf[100];
2932  if(data.GetRadiation().GetWavelengthType()==WAVELENGTH_TOF) mName+="TOF:";
2933  else
2934  {
2935  sprintf(buf,"%6.3fA:",data.GetWavelength()(0));
2936  mName+=buf;
2937  }
2938  mName+=data.GetName();
2939 
2940  }
2941  if(mType==0) mName="(Fo)"+mName;
2942  if(mType==1) mName="(Fc)"+mName;
2943  if(mType==2) mName="(Fo-Fc)"+mName;
2944  return 1;
2945 }
2946 #endif
2947 
2948 const string & UnitCellMap::GetName()const
2949 {
2950  return mName;
2951 }
2952 
2953 REAL UnitCellMap::GetValue(const REAL x,const REAL y,const REAL z)const
2954 {
2955  const int nx=mPoints.cols();
2956  const int ny=mPoints.rows();
2957  const int nz=mPoints.depth();
2958  long ix=((long)floor(x*nx+.5))%nx;
2959  long iy=((long)floor(y*ny+.5))%ny;
2960  long iz=((long)floor(z*nz+.5))%nz;
2961  if(ix<0) ix+=nx;
2962  if(iy<0) iy+=ny;
2963  if(iz<0) iz+=nz;
2964  return mPoints(iz,iy,ix);
2965 }
2966 REAL UnitCellMap::Max()const{return mMax;}
2967 REAL UnitCellMap::Min()const{return mMin;}
2968 REAL UnitCellMap::Mean()const{return mMean;}
2969 REAL UnitCellMap::StandardDeviation()const{return mStandardDeviation;}
2970 int UnitCellMap::GetType()const{return mType;}
2971 const Crystal &UnitCellMap::GetCrystal()const{return *mpCrystal;}
2972 const ScatteringData *UnitCellMap::GetData()const{return mpData;}
2973 
2975 //
2976 // UnitCellMapGLList
2977 //
2979 UnitCellMapGLList::UnitCellMapGLList(const UnitCellMap &ucmap,WXGLCrystalCanvas * parent,
2980  const bool showWire,float contour,
2981  const float r,const float g,const float b,const float t):
2982 mGLDisplayList(0),mShowWire(showWire),mShow(true),mContour(contour),mpUCMap(&ucmap),mpParent(parent)
2983 {
2984  VFN_DEBUG_MESSAGE("UnitCellMapGLList::UnitCellMapGLList()",10)
2985  this->SetColour(r,g,b,t);
2986 }
2987 
2988 UnitCellMapGLList::~UnitCellMapGLList()
2989 {
2990  VFN_DEBUG_MESSAGE("UnitCellMapGLList::~UnitCellMapGLList()",10)
2991  if(0!=mGLDisplayList) glDeleteLists(mGLDisplayList,1);
2992 }
2993 void UnitCellMapGLList::GenList()
2994 {
2995  VFN_DEBUG_ENTRY("UnitCellMapGLList::GenList()",7)
2996  if(0==mGLDisplayList) mGLDisplayList=glGenLists(1);
2997  glNewList(mGLDisplayList,GL_COMPILE);
2998  glPushMatrix();
2999  mpUCMap->GLInitDisplayList(mContour, mpParent);
3000  glPopMatrix();
3001  glEndList();
3002  VFN_DEBUG_EXIT("UnitCellMapGLList::GenList()",7)
3003 }
3004 
3005 void UnitCellMapGLList::SetColour(const float r,const float g,const float b,
3006  const float t)
3007 {
3008  mColour[0]=r;
3009  mColour[1]=g;
3010  mColour[2]=b;
3011  mColour[3]=t;
3012 }
3013 
3014 const float* UnitCellMapGLList::GetColour()const
3015 {
3016  return mColour;
3017 }
3018 
3019 void UnitCellMapGLList::ToggleShowWire()
3020 {
3021  mShowWire =! mShowWire;
3022 }
3023 
3024 bool UnitCellMapGLList::ShowWire()const
3025 {
3026  return mShowWire;
3027 }
3028 
3029 void UnitCellMapGLList::Draw()const
3030 {
3031  if(0==mGLDisplayList)
3032  {
3033  VFN_DEBUG_MESSAGE("UnitCellMapGLList::Draw():No Display list generated !",7)
3034  return;
3035  }
3036  glPushMatrix();
3037  if(mShowWire) glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
3038  else glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
3039 
3040  glMaterialfv(GL_FRONT, GL_AMBIENT, mColour);
3041  glMaterialfv(GL_FRONT, GL_DIFFUSE, mColour);
3042  glMaterialfv(GL_FRONT, GL_SPECULAR, mColour);
3043  const GLfloat colour0[] = {0.0f, 0.0f, 0.0f, 0.0f};
3044  glMaterialfv(GL_FRONT, GL_EMISSION, colour0);
3045  // :TODO:
3046  // Disabled Shininess as there is a problem with normals
3047  // and non-orthogonal unit cells
3048  glMaterialf( GL_FRONT, GL_SHININESS, 0.0);
3049 
3050  const GLfloat colorBack [] = {mColour[0]/3.0f, mColour[1]/3.0f, mColour[2]/3.0f, mColour[3]};
3051  glMaterialfv(GL_BACK, GL_AMBIENT, colorBack);
3052  glMaterialfv(GL_BACK, GL_DIFFUSE, colorBack);
3053  glMaterialfv(GL_BACK, GL_SPECULAR, colorBack);
3054  glMaterialf( GL_BACK, GL_SHININESS, 0.0);
3055  // :TODO: Check display list is not being modified (lock it), useless for now
3056  // as the map is not dynamically updated.
3057  glCallList(mGLDisplayList);
3058  glPopMatrix();
3059  VFN_DEBUG_EXIT("UnitCellMapGLList::Draw()",7)
3060 }
3061 
3062 void UnitCellMapGLList::SetName(const string &name)
3063 {
3064  mName=name;
3065 }
3066 const string &UnitCellMapGLList::GetName()const
3067 {
3068  return mName;
3069 }
3070 void UnitCellMapGLList::SetShow(bool show) {mShow=show;}
3071 bool UnitCellMapGLList::Show()const {return mShow;}
3072 void UnitCellMapGLList::SetContour(float contour) {mContour=contour;}
3073 float UnitCellMapGLList::GetContour()const {return mContour;}
3074 const UnitCellMap & UnitCellMapGLList::GetMap()const {return *mpUCMap;}
3076 //
3077 // WXGLCrystalCanvas::WXFourierMapList
3078 //
3080 
3081 WXGLCrystalCanvas::WXFourierMapList::WXFourierMapList(WXGLCrystalCanvas *pGLCrystalCanvas,wxWindow *parent):
3082 wxWindow(parent,-1),mpGLCrystalCanvas(pGLCrystalCanvas),mIsUpdating(false)
3083 {
3084  this->SetFont(wxFont(8,wxTELETYPE,wxFONTSTYLE_NORMAL,wxFONTWEIGHT_NORMAL));
3085  wxBoxSizer* pSizer=new wxBoxSizer(wxVERTICAL);
3086  // Top buttons
3087  wxBoxSizer* pSizerButtons=new wxBoxSizer(wxHORIZONTAL);
3088  wxButton *pButtonUpdate=new wxButton(this,ID_GLCRYSTAL_FOURIER_UPDATE,_T("Update 3D View"));
3089  mpWireFrame=new wxCheckBox(this,ID_GLCRYSTAL_FOURIER_WIREFRAME,_T("Wireframe"));
3090  mpShowFourier=new wxCheckBox(this,ID_GLCRYSTAL_FOURIER_SHOW,_T("Show Fourier"));
3091  mpSharpenMap=new wxCheckBox(this,ID_GLCRYSTAL_FOURIER_SHARPEN,_T("Sharpen maps"));
3092  pSizerButtons->Add(pButtonUpdate,0,wxALIGN_CENTER);
3093  pSizerButtons->Add(mpWireFrame,0,wxALIGN_CENTER);
3094  pSizerButtons->Add(mpShowFourier,0,wxALIGN_CENTER);
3095  pSizerButtons->Add(mpSharpenMap,0,wxALIGN_CENTER);
3096  pSizer->Add(pSizerButtons,0,wxALIGN_CENTER);
3097 
3098  // Map lists
3099  wxBoxSizer* pSizerMaps=new wxBoxSizer(wxHORIZONTAL);
3100 
3101  // Left column - available maps
3102  wxBoxSizer* pSizerLeft=new wxBoxSizer(wxVERTICAL);
3103  pSizerMaps->Add(pSizerLeft,0,wxALIGN_TOP);
3104 
3105  wxStaticText *mpLabel0=new wxStaticText(this,-1,_T("Available Maps"));
3106  pSizerLeft->Add(mpLabel0,0,wxALIGN_CENTER);
3107  mpAvailableMapList=new wxListBox(this,ID_GLCRYSTAL_FOURIER_LISTMAP,wxDefaultPosition,wxSize(400,150));
3108  pSizerLeft->Add(mpAvailableMapList,0,wxALIGN_CENTER);
3109 
3110  mpMapInfo=new wxStaticText(this,-1,_T("min=+00.00 max=+00.00 sigma=00.00"));
3111  pSizerLeft->Add(mpMapInfo,0,wxALIGN_CENTER);
3112 
3113  wxBoxSizer* pSizerLeft2=new wxBoxSizer(wxHORIZONTAL);
3114  pSizerLeft->Add(pSizerLeft2,0,wxALIGN_CENTER);
3115  wxStaticText *mpLabel2=new wxStaticText(this,-1,_T("New Contour:"));
3116  mpNewContourValue=new wxTextCtrl(this,ID_GLCRYSTAL_FOURIER_NEWCONTOUR,_T(""),wxDefaultPosition,wxDefaultSize,
3117  wxTE_PROCESS_ENTER,wxTextValidator(wxFILTER_NUMERIC));
3118  pSizerLeft2->Add(mpLabel2,0,wxALIGN_CENTER);
3119  pSizerLeft2->Add(mpNewContourValue,0,wxALIGN_CENTER);
3120 
3121  wxButton *pButtonAdd=new wxButton(this,ID_GLCRYSTAL_FOURIER_ADD,_T("Add"));
3122  pSizerLeft->Add(pButtonAdd,0,wxALIGN_CENTER);
3123 
3124  pSizerMaps->AddSpacer(5);
3125  // Right column - displayed maps & contours
3126  wxBoxSizer* pSizerRight=new wxBoxSizer(wxVERTICAL);
3127  pSizerMaps->Add(pSizerRight,0,wxALIGN_TOP);
3128 
3129  wxStaticText *mpLabel0r=new wxStaticText(this,-1,_T("Displayed Maps"));
3130  pSizerRight->Add(mpLabel0r,0,wxALIGN_CENTER);
3131  mpDisplayedMapList=new wxListBox(this,ID_GLCRYSTAL_FOURIER_LISTGLMAP,wxDefaultPosition,wxSize(400,150));
3132  pSizerRight->Add(mpDisplayedMapList,0,wxALIGN_CENTER);
3133 
3134  wxBoxSizer* pSizerRight1=new wxBoxSizer(wxHORIZONTAL);
3135  pSizerRight->Add(pSizerRight1,0,wxALIGN_CENTER);
3136  wxStaticText *mpLabel3=new wxStaticText(this,-1,_T("Contour:"));
3137  mpContourValue=new wxTextCtrl(this,ID_GLCRYSTAL_FOURIER_CONTOUR,_T(""),wxDefaultPosition,wxDefaultSize,
3138  wxTE_PROCESS_ENTER,wxTextValidator(wxFILTER_NUMERIC));
3139  pSizerRight1->Add(mpLabel3,0,wxALIGN_CENTER);
3140  pSizerRight1->Add(mpContourValue,0,wxALIGN_CENTER);
3141 
3142  mpColourPicker=new wxColourPickerCtrl(this, ID_GLCRYSTAL_FOURIER_COLOURPICKER, *wxRED, wxDefaultPosition, wxDefaultSize,wxCLRP_USE_TEXTCTRL);
3143  wxButton *pButtonRemove=new wxButton(this,ID_GLCRYSTAL_FOURIER_REMOVE,_T("Remove"));
3144  pSizerRight->Add(mpColourPicker,0,wxALIGN_CENTER);
3145  pSizerRight->Add(pButtonRemove,0,wxALIGN_CENTER);
3146  pSizer->Add(pSizerMaps,0,wxALIGN_CENTER);
3147  this->SetSizer(pSizer);
3148  this->SetAutoLayout(true);
3149  pSizer->SetSizeHints(this);
3150  pSizer->SetSizeHints(parent);
3151  this->Layout();
3152 }
3153 WXGLCrystalCanvas::WXFourierMapList::~WXFourierMapList()
3154 {
3155  mpGLCrystalCanvas->NotifyDeleteFourierWin();
3156 }
3157 
3158 struct GLCrystalConfig
3159 {
3160  GLCrystalConfig(const bool saved=false);
3161  float mDist;
3162  REAL mX0, mY0,mZ0;
3163  float mViewAngle;
3164  float mQuat [4];
3165  bool mSaved;
3166  bool mShowAtomName;
3167  bool mShowCursor;
3168  BBox mcellbbox;
3169  BBox mmapbbox;
3170  Triple mViewCntr;
3171 };
3172 
3173 GLCrystalConfig::GLCrystalConfig(const bool saved)
3174 {
3175  mSaved=saved;
3176 }
3177 
3178 static GLCrystalConfig sGLCrystalConfig;
3179 
3181 //
3182 // WXGLCrystalCanvas
3183 //
3185 static const long ID_GLCRYSTAL_MENU_SHOWATOMLABEL= WXCRYST_ID();
3186 static const long ID_GLCRYSTAL_MENU_SHOWHYDROGENS= WXCRYST_ID();
3187 static const long ID_GLCRYSTAL_MENU_SHOWCURSOR= WXCRYST_ID();
3188 static const long ID_GLCRYSTAL_MENU_SETCURSOR= WXCRYST_ID();
3189 static const long ID_GLCRYSTAL_UPDATEUI= WXCRYST_ID();
3190 static const long ID_GLCRYSTAL_MENU_CHANGELIMITS= WXCRYST_ID();
3191 static const long ID_GLCRYSTAL_MENU_LIMITS_FULLCELL= WXCRYST_ID();
3192 static const long ID_GLCRYSTAL_MENU_LIMITS_ASYMCELL= WXCRYST_ID();
3193 static const long ID_GLCRYSTAL_MENU_SHOWCRYSTAL= WXCRYST_ID();
3194 static const long ID_GLCRYSTAL_MENU_FOURIER= WXCRYST_ID();
3195 static const long ID_GLCRYSTAL_MENU_LOADFOURIERGRD= WXCRYST_ID();
3196 static const long ID_GLCRYSTAL_MENU_LOADFOURIERDSN6= WXCRYST_ID();
3197 //static const long ID_GLCRYSTAL_MENU_UNLOADFOURIER= WXCRYST_ID();
3198 static const long ID_GLCRYSTAL_MENU_POVRAY= WXCRYST_ID();
3199 static const long ID_GLCRYSTAL_MENU_SHOWHELP= WXCRYST_ID();
3200 
3201 
3202 BEGIN_EVENT_TABLE(WXGLCrystalCanvas, wxGLCanvas)
3203  EVT_PAINT (WXGLCrystalCanvas::OnPaint)
3204  EVT_ERASE_BACKGROUND (WXGLCrystalCanvas::OnEraseBackground)
3205  EVT_MOUSE_EVENTS (WXGLCrystalCanvas::OnMouse)
3206  EVT_MENU (ID_GLCRYSTAL_MENU_UPDATE, WXGLCrystalCanvas::OnUpdate)
3207  EVT_MENU (ID_GLCRYSTAL_MENU_CHANGELIMITS, WXGLCrystalCanvas::OnChangeLimits)
3208  EVT_MENU (ID_GLCRYSTAL_MENU_LIMITS_FULLCELL, WXGLCrystalCanvas::OnChangeLimits)
3209  EVT_MENU (ID_GLCRYSTAL_MENU_LIMITS_ASYMCELL, WXGLCrystalCanvas::OnChangeLimits)
3210  EVT_MENU (ID_GLCRYSTAL_MENU_SHOWCRYSTAL, WXGLCrystalCanvas::OnShowCrystal)
3211  EVT_MENU (ID_GLCRYSTAL_MENU_SHOWATOMLABEL, WXGLCrystalCanvas::OnShowAtomLabel)
3212  EVT_MENU (ID_GLCRYSTAL_MENU_SHOWHYDROGENS, WXGLCrystalCanvas::OnShowHydrogens)
3213  EVT_MENU (ID_GLCRYSTAL_MENU_SHOWCURSOR, WXGLCrystalCanvas::OnShowCursor)
3214  EVT_MENU (ID_GLCRYSTAL_MENU_SETCURSOR, WXGLCrystalCanvas::OnSetCursor)
3215  EVT_MENU (ID_GLCRYSTAL_MENU_SHOWHELP, WXGLCrystalCanvas::OnShowHelp)
3216  EVT_MENU (ID_GLCRYSTAL_MENU_LOADFOURIERGRD, WXGLCrystalCanvas::OnLoadFourierGRD)
3217  EVT_MENU (ID_GLCRYSTAL_MENU_LOADFOURIERDSN6, WXGLCrystalCanvas::OnLoadFourierDSN6)
3218 // EVT_MENU (ID_GLCRYSTAL_MENU_UNLOADFOURIER, WXGLCrystalCanvas::OnUnloadFourier)
3219  EVT_MENU (ID_GLCRYSTAL_MENU_POVRAY, WXGLCrystalCanvas::OnPOVRay)
3220  EVT_MENU (ID_GLCRYSTAL_MENU_FOURIER, WXGLCrystalCanvas::OnFourier)
3221  EVT_LISTBOX (ID_GLCRYSTAL_FOURIER_LISTGLMAP, WXGLCrystalCanvas::OnFourier)
3222  EVT_LISTBOX (ID_GLCRYSTAL_FOURIER_LISTMAP, WXGLCrystalCanvas::OnFourier)
3223  EVT_BUTTON (ID_GLCRYSTAL_FOURIER_ADD, WXGLCrystalCanvas::OnFourier)
3224  EVT_BUTTON (ID_GLCRYSTAL_FOURIER_REMOVE, WXGLCrystalCanvas::OnFourier)
3225  EVT_BUTTON (ID_GLCRYSTAL_FOURIER_UPDATE, WXGLCrystalCanvas::OnFourier)
3226  EVT_CHECKBOX (ID_GLCRYSTAL_FOURIER_WIREFRAME, WXGLCrystalCanvas::OnFourier)
3227  EVT_CHECKBOX (ID_GLCRYSTAL_FOURIER_SHOW, WXGLCrystalCanvas::OnFourier)
3228  EVT_CHECKBOX (ID_GLCRYSTAL_FOURIER_SHARPEN, WXGLCrystalCanvas::OnFourier)
3229  EVT_TEXT_ENTER (ID_GLCRYSTAL_FOURIER_NEWCONTOUR, WXGLCrystalCanvas::OnFourier)
3230  EVT_TEXT_ENTER (ID_GLCRYSTAL_FOURIER_CONTOUR, WXGLCrystalCanvas::OnFourier)
3231  EVT_COLOURPICKER_CHANGED(ID_GLCRYSTAL_FOURIER_COLOURPICKER, WXGLCrystalCanvas::OnFourierChangeColour)
3232  EVT_CHAR (WXGLCrystalCanvas::OnKeyDown)
3233  EVT_KEY_DOWN (WXGLCrystalCanvas::OnKeyDown)
3234  EVT_KEY_UP (WXGLCrystalCanvas::OnKeyUp)
3235  EVT_UPDATE_UI(ID_GLCRYSTAL_UPDATEUI,WXGLCrystalCanvas::OnUpdateUI)
3236 END_EVENT_TABLE()
3237 
3238 int AttribList [] = {WX_GL_RGBA , WX_GL_DOUBLEBUFFER, WX_GL_DEPTH_SIZE, 16,0};
3239 
3240 WXGLCrystalCanvas::WXGLCrystalCanvas(WXCrystal *wxcryst,
3241  wxFrame *parent, wxWindowID id,
3242  const wxPoint &pos,
3243  const wxSize &size):
3244 wxGLCanvas(parent, id,AttribList,pos,size,wxDEFAULT_FRAME_STYLE | wxFULL_REPAINT_ON_RESIZE,_T("GLCanvas"),wxNullPalette),
3245 //wxGLCanvas(parent,id,pos,size,wxDEFAULT_FRAME_STYLE,_T("GLCanvas"),AttribList),
3246 mpParentFrame(parent),
3247 mpWXCrystal(wxcryst),mIsGLInit(false),mDist(60),mX0(0),mY0(0),mZ0(0),mViewAngle(15),
3248 mShowFourier(true),mShowCrystal(true),mShowAtomName(true),mShowHydrogens(true),
3249 mShowCursor(false),mSharpenMap(true),mShowHelp(false),mShowFullMolecule(false), mWhiteBackground(false),
3250 mIsGLFontBuilt(false),mGLFontDisplayListBase(0),mpFourierMapListWin(0),mFadeDistance(0)
3251 {
3252  mpwxGLContext=new wxGLContext(this);
3253  VFN_DEBUG_MESSAGE("WXGLCrystalCanvas::WXGLCrystalCanvas()",3)
3254  if(sGLCrystalConfig.mSaved)
3255  {
3256  mDist=sGLCrystalConfig.mDist;
3257  mX0=sGLCrystalConfig.mX0;
3258  mY0=sGLCrystalConfig.mY0;
3259  mZ0=sGLCrystalConfig.mZ0;
3260  mViewAngle=sGLCrystalConfig.mViewAngle;
3261  for(int i=0;i<4;++i) mQuat[i]=sGLCrystalConfig.mQuat[i];
3262  mShowAtomName=sGLCrystalConfig.mShowAtomName;
3263  mShowCursor=sGLCrystalConfig.mShowCursor;
3264 
3265  mcellbbox.xMin=sGLCrystalConfig.mcellbbox.xMin;
3266  mcellbbox.xMax=sGLCrystalConfig.mcellbbox.xMax;
3267  mcellbbox.yMin=sGLCrystalConfig.mcellbbox.yMin;
3268  mcellbbox.yMax=sGLCrystalConfig.mcellbbox.yMax;
3269  mcellbbox.zMin=sGLCrystalConfig.mcellbbox.zMin;
3270  mcellbbox.zMax=sGLCrystalConfig.mcellbbox.zMax;
3271 
3272  mmapbbox.xMin=sGLCrystalConfig.mmapbbox.xMin;
3273  mmapbbox.xMax=sGLCrystalConfig.mmapbbox.xMax;
3274  mmapbbox.yMin=sGLCrystalConfig.mmapbbox.yMin;
3275  mmapbbox.yMax=sGLCrystalConfig.mmapbbox.yMax;
3276  mmapbbox.zMin=sGLCrystalConfig.mmapbbox.zMin;
3277  mmapbbox.zMax=sGLCrystalConfig.mmapbbox.zMax;
3278 
3279  mViewCntr.x=sGLCrystalConfig.mViewCntr.x;
3280  mViewCntr.y=sGLCrystalConfig.mViewCntr.y;
3281  mViewCntr.z=sGLCrystalConfig.mViewCntr.z;
3282  }
3283  else
3284  {
3285  mcellbbox.xMin = mpWXCrystal->GetCrystal().GetSpaceGroup().GetAsymUnit().Xmin();
3286  mcellbbox.yMin = mpWXCrystal->GetCrystal().GetSpaceGroup().GetAsymUnit().Ymin();
3287  mcellbbox.zMin = mpWXCrystal->GetCrystal().GetSpaceGroup().GetAsymUnit().Zmin();
3288  mcellbbox.xMax = mpWXCrystal->GetCrystal().GetSpaceGroup().GetAsymUnit().Xmax();
3289  mcellbbox.yMax = mpWXCrystal->GetCrystal().GetSpaceGroup().GetAsymUnit().Ymax();
3290  mcellbbox.zMax = mpWXCrystal->GetCrystal().GetSpaceGroup().GetAsymUnit().Zmax();
3291  }
3292  // N.B. xMin=xMax so that the previous cell bbox is used for Maps
3293  // until mmapbbox is changed
3294  mmapbbox.xMin = mmapbbox.xMax = mmapbbox.yMin = mmapbbox.zMin = 0.;
3295  mmapbbox.yMax = mmapbbox.zMax = 1.;
3296  mpPopUpMenu=new wxMenu(_T("Crystal"));
3297  mpPopUpMenu->Append(ID_GLCRYSTAL_MENU_UPDATE, _T("&Update"));
3298  mpPopUpMenu->AppendSeparator();
3299  mpPopUpMenu->Append(ID_GLCRYSTAL_MENU_CHANGELIMITS, _T("Change display &Limits"));
3300  mpPopUpMenu->Append(ID_GLCRYSTAL_MENU_LIMITS_FULLCELL, _T("Show Full Unit Cell"));
3301  mpPopUpMenu->Append(ID_GLCRYSTAL_MENU_LIMITS_ASYMCELL, _T("Show Asymmetric Unit Cell"));
3302  mpPopUpMenu->AppendSeparator();
3303  mpPopUpMenu->Append(ID_GLCRYSTAL_MENU_SHOWCRYSTAL, _T("Hide Crystal"));
3304  mpPopUpMenu->Append(ID_GLCRYSTAL_MENU_SHOWATOMLABEL, _T("Hide Atom Labels"));
3305  mpPopUpMenu->Append(ID_GLCRYSTAL_MENU_SHOWHYDROGENS, _T("Hide Hydrogens"));
3306  mpPopUpMenu->Append(ID_GLCRYSTAL_MENU_SHOWCURSOR, _T("Show Cursor"));
3307  mpPopUpMenu->Append(ID_GLCRYSTAL_MENU_SETCURSOR, _T("Set view cntr and cursor pos."));
3308  mpPopUpMenu->Append(ID_GLCRYSTAL_MENU_POVRAY, _T("Create POVRay file"));
3309  mpPopUpMenu->AppendSeparator();
3310  mpPopUpMenu->Append(ID_GLCRYSTAL_MENU_FOURIER, _T("Fourier Maps"));
3311  mpPopUpMenu->Append(ID_GLCRYSTAL_MENU_LOADFOURIERGRD, _T("Load GRD Fourier Map"));
3312  mpPopUpMenu->Append(ID_GLCRYSTAL_MENU_LOADFOURIERDSN6,_T("Load DSN6 Fourier Map"));
3313  mpPopUpMenu->AppendSeparator();
3314  mpPopUpMenu->Append(ID_GLCRYSTAL_MENU_SHOWHELP, _T("Show &Help"));
3315  /*
3316  mpPopUpMenu->Append(ID_GLCRYSTAL_MENU_UNLOADFOURIER, "Unload Fourier Map(s)");
3317  mpPopUpMenu->Enable(ID_GLCRYSTAL_MENU_UNLOADFOURIER, FALSE);
3318  */
3319  if(sGLCrystalConfig.mSaved==false)
3320  {
3321  if(!wxConfigBase::Get()->HasEntry(_T("Crystal/BOOL/Default-display only asymmetric unit cell in 3D view")))
3322  wxConfigBase::Get()->Write(_T("Crystal/BOOL/Default-display only asymmetric unit cell in 3D view"), true);
3323  else
3324  {
3325  bool val;
3326  wxConfigBase::Get()->Read(_T("Crystal/BOOL/Default-display only asymmetric unit cell in 3D view"), &val);
3327  if(val)
3328  {
3329  mcellbbox.xMin = mpWXCrystal->GetCrystal().GetSpaceGroup().GetAsymUnit().Xmin();
3330  mcellbbox.yMin = mpWXCrystal->GetCrystal().GetSpaceGroup().GetAsymUnit().Ymin();
3331  mcellbbox.zMin = mpWXCrystal->GetCrystal().GetSpaceGroup().GetAsymUnit().Zmin();
3332  mcellbbox.xMax = mpWXCrystal->GetCrystal().GetSpaceGroup().GetAsymUnit().Xmax();
3333  mcellbbox.yMax = mpWXCrystal->GetCrystal().GetSpaceGroup().GetAsymUnit().Ymax();
3334  mcellbbox.zMax = mpWXCrystal->GetCrystal().GetSpaceGroup().GetAsymUnit().Zmax();
3335  }
3336  else
3337  {
3338  mcellbbox.xMin = 0;
3339  mcellbbox.yMin = 0;
3340  mcellbbox.zMin = 0;
3341  mcellbbox.xMax = 1;
3342  mcellbbox.yMax = 1;
3343  mcellbbox.zMax = 1;
3344  }
3345  }
3346  if(!wxConfigBase::Get()->HasEntry(_T("Crystal/BOOL/Default-display atom names in 3D view")))
3347  wxConfigBase::Get()->Write(_T("Crystal/BOOL/Default-display atom names in 3D view"), mShowAtomName);
3348  else
3349  {
3350  wxConfigBase::Get()->Read(_T("Crystal/BOOL/Default-display atom names in 3D view"), &mShowAtomName);
3351  }
3352  }
3353  // Fade distance for showing transparent atoms beyond display limit
3354  if(!wxConfigBase::Get()->HasEntry(_T("Crystal/REAL/3D fade distance")))
3355  wxConfigBase::Get()->Write(_T("Crystal/REAL/3D fade distance"), 4);
3356 
3357  wxConfigBase::Get()->Read(_T("Crystal/REAL/3D fade distance"), &mFadeDistance);
3358 
3359  // Show full molecules for those centered inside the display limits ?
3360  if(!wxConfigBase::Get()->HasEntry(_T("Crystal/BOOL/Show full molecules in 3D view")))
3361  wxConfigBase::Get()->Write(_T("Crystal/BOOL/Show full molecules in 3D view"), mShowFullMolecule);
3362 
3363  wxConfigBase::Get()->Read(_T("Crystal/BOOL/Show full molecules in 3D view"), &mShowFullMolecule);
3364 
3365  if(mShowAtomName) mpPopUpMenu->SetLabel(ID_GLCRYSTAL_MENU_SHOWATOMLABEL, _T("Hide Atom Labels"));
3366  else mpPopUpMenu->SetLabel(ID_GLCRYSTAL_MENU_SHOWATOMLABEL, _T("Show Atom Labels"));
3367 }
3368 
3369 WXGLCrystalCanvas::~WXGLCrystalCanvas()
3370 {
3371  mpWXCrystal->NotifyCrystalGLDelete();
3372  #ifndef HAVE_GLUT
3373  this->DeleteGLFont();
3374  #endif
3375  // The frame position is saved in ~WXGLCrystalCanvasFrame() to store position before the frame decoration are destroyed
3376  sGLCrystalConfig.mDist = mDist;
3377  sGLCrystalConfig.mX0=mX0;
3378  sGLCrystalConfig.mY0=mY0;
3379  sGLCrystalConfig.mZ0=mZ0;
3380  sGLCrystalConfig.mViewAngle=mViewAngle;
3381  for(int i=0;i<4;++i) sGLCrystalConfig.mQuat[i]=mQuat[i];
3382  sGLCrystalConfig.mShowAtomName=mShowAtomName;
3383  sGLCrystalConfig.mShowCursor=mShowCursor;
3384 
3385  sGLCrystalConfig.mcellbbox.xMin=mcellbbox.xMin;
3386  sGLCrystalConfig.mcellbbox.xMax=mcellbbox.xMax;
3387  sGLCrystalConfig.mcellbbox.yMin=mcellbbox.yMin;
3388  sGLCrystalConfig.mcellbbox.yMax=mcellbbox.yMax;
3389  sGLCrystalConfig.mcellbbox.zMin=mcellbbox.zMin;
3390  sGLCrystalConfig.mcellbbox.zMax=mcellbbox.zMax;
3391 
3392  sGLCrystalConfig.mmapbbox.xMin=mmapbbox.xMin;
3393  sGLCrystalConfig.mmapbbox.xMax=mmapbbox.xMax;
3394  sGLCrystalConfig.mmapbbox.yMin=mmapbbox.yMin;
3395  sGLCrystalConfig.mmapbbox.yMax=mmapbbox.yMax;
3396  sGLCrystalConfig.mmapbbox.zMin=mmapbbox.zMin;
3397  sGLCrystalConfig.mmapbbox.zMax=mmapbbox.zMax;
3398 
3399  sGLCrystalConfig.mViewCntr.x=mViewCntr.x;
3400  sGLCrystalConfig.mViewCntr.y=mViewCntr.y;
3401  sGLCrystalConfig.mViewCntr.z=mViewCntr.z;
3402  sGLCrystalConfig.mSaved=true;
3403  delete mpwxGLContext;
3404 }
3405 
3406 void WXGLCrystalCanvas::OnExit(wxCommandEvent &event)
3407 {
3408 
3409 }
3410 
3411 void WXGLCrystalCanvas::OnPaint(wxPaintEvent &event)
3412 {
3413  VFN_DEBUG_ENTRY("WXGLCrystalCanvas::OnPaint()",7)
3414  wxPaintDC dc(this);
3415  this->SetCurrent();
3416  if(false==mIsGLInit)
3417  {
3418  mIsGLInit=true;
3419  this->InitGL();
3420  }
3421 
3422  {
3423  int width, height;
3424  GetClientSize(& width, & height);
3425 
3426  this->SetCurrent();
3427  glViewport(0, 0, width, height);
3428  glMatrixMode(GL_PROJECTION);
3429  glLoadIdentity();
3430  if( (width>0)&&(height>0)) //in case the window is docked...
3431  gluPerspective(mViewAngle,(float)width/(float)height,1.f,2.*mDist);
3432 
3433  }
3434  glMatrixMode( GL_MODELVIEW );
3435 
3436  //clear
3437  if(mWhiteBackground) glClearColor(1.0f, 1.0f, 1.0f, 1.0f); // White background
3438  else glClearColor(0.0f, 0.0f, 0.0f, 1.0f); // Black background
3439  glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
3440 
3441  //Orientation using the trackball
3442  GLfloat m[4][4];
3443  glLoadIdentity();
3444  glTranslatef( 0, 0, -mDist );
3445  build_rotmatrix( m,mQuat);
3446  glMultMatrixf( &m[0][0] );
3447  glTranslatef( mX0, mY0, mZ0 );
3448 
3449  //Draw first non-transparent object then transparent ones
3450  for(unsigned int passnum = 0; passnum<2; passnum++)
3451  {
3452  if (passnum == 0)
3453  {
3454  glDepthMask(GL_TRUE);
3455  glAlphaFunc(GL_GREATER,0.99);
3456  }
3457  else
3458  {
3459  glDepthMask(GL_FALSE);
3460  glAlphaFunc(GL_LEQUAL,0.99);
3461  }
3462  if(mShowCrystal)
3463  {
3464  glLoadIdentity();
3465  if(mWhiteBackground) glColor3f(0.0,0.0,0.0);
3466  else glColor3f(1.0,1.0,1.0);
3467  glTranslatef(0, 0, -mDist);
3468  glMultMatrixf(&m[0][0]);
3469  glTranslatef(mX0, mY0, mZ0);
3470  glCallList(mpWXCrystal->GetCrystalGLDisplayList()); //Draw Crystal
3471  if(mShowAtomName)
3472  {
3473  glLoadIdentity();
3474  if(mWhiteBackground) glColor3f(0.0,0.0,0.0);
3475  else glColor3f(1.0,1.0,1.0);
3476  glTranslatef( -0.3, 0, -mDist+1. );// Put labels in front of the atom position
3477  glMultMatrixf( &m[0][0] );
3478  glTranslatef( mX0, mY0, mZ0 );
3479  glCallList(mpWXCrystal->GetCrystalGLDisplayList(true)); //Draw Atom Names
3480  }
3481 
3482  }
3483  {//Show display limits and help text
3484  int w, h;
3485  GetClientSize(& w, & h);
3486  GLfloat colour2 [] = {1.00, 1.00, 1.00, 0.3};
3487  if(mWhiteBackground)
3488  for(unsigned int i=0;i<3;i++) colour2[i] = 0.0;
3489  else
3490  for(unsigned int i=0;i<3;i++) colour2[i] = 1.0;
3491 
3492  glMaterialfv(GL_FRONT, GL_EMISSION, colour2);
3493  glPushMatrix();
3494  glLoadIdentity();
3495  glMatrixMode(GL_PROJECTION);
3496  glPushMatrix();
3497  glLoadIdentity();
3498  gluOrtho2D(0,w,0,h);
3499  if(mWhiteBackground) glColor3f(0.0,0.0,0.0);
3500  else glColor3f(1.0,1.0,1.0);
3501  unsigned int i=1;
3502  glRasterPos2i(2,h-12*i);
3503  char c[256];
3504  sprintf(c,"%5.3f<x<%5.3f\n",mcellbbox.xMin,mcellbbox.xMax);
3505  crystGLPrint(c);
3506  i++;
3507 
3508  glRasterPos2i(2, h-12*i);
3509  sprintf(c,"%5.3f<y<%5.3f\n",mcellbbox.yMin,mcellbbox.yMax);
3510  crystGLPrint(c);
3511  i++;
3512 
3513  glRasterPos2i(2, h-12*i);
3514  sprintf(c,"%5.3f<z<%5.3f\n",mcellbbox.zMin,mcellbbox.zMax);
3515  crystGLPrint(c);
3516  i++;
3517 
3518  if(mShowHelp)
3519  {
3520  glRasterPos2i(2, h-12*i);
3521  sprintf(c,"Mouse");
3522  crystGLPrint(c);
3523  i++;
3524  glRasterPos2i(2, h-12*i);
3525  sprintf(c," left-click & drag: change orientation");
3526  crystGLPrint(c);
3527  i++;
3528  glRasterPos2i(2, h-12*i);
3529  sprintf(c," middle-click & drag: zoom (vert) change depth perception (horiz)");
3530  crystGLPrint(c);
3531  i++;
3532  glRasterPos2i(2, h-12*i);
3533  sprintf(c," wheel: rotate");
3534  crystGLPrint(c);
3535  i++;
3536 
3537  glRasterPos2i(2, h-12*i);
3538  sprintf(c,"Trackpad");
3539  crystGLPrint(c);
3540  i++;
3541  glRasterPos2i(2, h-12*i);
3542  sprintf(c," two-finger drag: change orientation");
3543  crystGLPrint(c);
3544  i++;
3545 
3546  glRasterPos2i(2, h-12*i);
3547  sprintf(c,"Keyboard (all lowercase)");
3548  crystGLPrint(c);
3549  i++;
3550  glRasterPos2i(2, h-12*i);
3551  sprintf(c," +,-: change zoom");
3552  crystGLPrint(c);
3553  i++;
3554  glRasterPos2i(2, h-12*i);
3555  sprintf(c," 2,4,6,8,D,C,F,R: rotate");
3556  crystGLPrint(c);
3557  i++;
3558  glRasterPos2i(2, h-12*i);
3559  sprintf(c," F1,F2,F3,F4,F5,F6: increase/decrease display area");
3560  crystGLPrint(c);
3561  i++;
3562  glRasterPos2i(2, h-12*i);
3563  sprintf(c," shift+F1,F2,F3,F4,F5,F6: shift display area");
3564  crystGLPrint(c);
3565  i++;
3566  glRasterPos2i(2, h-12*i);
3567  sprintf(c," F7,F8: increase/decrease fade distance");
3568  crystGLPrint(c);
3569  i++;
3570  glRasterPos2i(2, h-12*i);
3571  sprintf(c," F9,F10: display area=asymmetric or full unit cell");
3572  crystGLPrint(c);
3573  i++;
3574  glRasterPos2i(2, h-12*i);
3575  sprintf(c," H: toggle help display");
3576  crystGLPrint(c);
3577  i++;
3578  glRasterPos2i(2, h-12*i);
3579  sprintf(c," L: toggle atom labels");
3580  crystGLPrint(c);
3581  i++;
3582  glRasterPos2i(2, h-12*i);
3583  sprintf(c," M: toggle full molecules");
3584  crystGLPrint(c);
3585  i++;
3586  glRasterPos2i(2, h-12*i);
3587  sprintf(c," Y: toggle hydrogens");
3588  crystGLPrint(c);
3589  i++;
3590  glRasterPos2i(2, h-12*i);
3591  sprintf(c," B: toggle white/black background");
3592  crystGLPrint(c);
3593  i++;
3594  }
3595  glPopMatrix();
3596  glMatrixMode( GL_MODELVIEW );
3597  glPopMatrix();
3598  }
3599  if(mShowCursor)
3600  {
3601  glLoadIdentity();
3602  glTranslatef( 0, 0, -mDist);
3603  glMultMatrixf( &m[0][0] );
3604  const GLfloat colour0 [] = {0.00, 0.00, 0.00, 0.00};
3605  const GLfloat colour1 [] = {1.0f, 1.0f, 1.0f, 1.00};
3606  glMaterialfv(GL_FRONT, GL_AMBIENT, colour1);
3607  glMaterialfv(GL_FRONT, GL_DIFFUSE, colour1);
3608  glMaterialfv(GL_FRONT, GL_SPECULAR, colour0);
3609  glMaterialfv(GL_FRONT, GL_EMISSION, colour1);
3610  glMaterialfv(GL_FRONT, GL_SHININESS, colour1);
3611  glBegin(GL_LINES);
3612  glVertex3f(-1.0f, 0.0f, 0.0f);
3613  glVertex3f( 1.0f, 0.0f, 0.0f);
3614 
3615  glVertex3f( 0.0f,-1.0f, 0.0f);
3616  glVertex3f( 0.0f, 1.0f, 0.0f);
3617 
3618  glVertex3f( 0.0f, 0.0f,-1.0f);
3619  glVertex3f( 0.0f, 0.0f, 1.0f);
3620  glEnd();
3621  }
3622  // Print position of center of image, plus intensity of Fourier maps (if any)
3623  {
3624  wxString statusText;
3625  REAL x=mX0;
3626  REAL y=mY0;
3627  REAL z=mZ0;
3628  mpWXCrystal->GetCrystal().OrthonormalToFractionalCoords(x,y,z);
3629  x=(mcellbbox.xMax+mcellbbox.xMin)/2.-x;
3630  y=(mcellbbox.yMax+mcellbbox.yMin)/2.-y;
3631  z=(mcellbbox.zMax+mcellbbox.zMin)/2.-z;
3632  statusText.Printf(_T("Center@(%5.3f,%5.3f,%5.3f)"),x,y,z);
3633  for(unsigned int i=0;i<mvpUnitCellMap.size();++i)
3634  {
3635  statusText+=_T(", map(") + wxString::FromAscii(mvpUnitCellMap[i]->GetName().c_str())
3636  +wxString::Format(_T(")=%5.2fe"),mvpUnitCellMap[i]->GetValue(x,y,z));
3637  }
3638  mpParentFrame->SetStatusText(statusText);
3639  }
3640  if (mShowFourier && (passnum==0))
3641  {
3642  glAlphaFunc(GL_ALWAYS,1);
3643  glLoadIdentity();
3644  glTranslatef( 0, 0, -mDist );
3645  build_rotmatrix( m,mQuat);
3646  glMultMatrixf( &m[0][0] );
3647  glTranslatef( mX0, mY0, mZ0 );
3648  glPushMatrix();
3649  // The display origin is the center of the Crystal BoundingBox, so translate
3650  BBox cellbbox = this->GetCellBBox();
3651  REAL xc=(cellbbox.xMin+cellbbox.xMax)/2.;
3652  REAL yc=(cellbbox.yMin+cellbbox.yMax)/2.;
3653  REAL zc=(cellbbox.zMin+cellbbox.zMax)/2.;
3654  mpWXCrystal->GetCrystal().FractionalToOrthonormalCoords(xc, yc, zc);
3655  glTranslatef(-xc, -yc, -zc);
3656  // Draw all Fourier maps
3657  vector<boost::shared_ptr<UnitCellMapGLList> >::const_iterator pos;
3658  for(pos=mvpUnitCellMapGLList.begin();pos != mvpUnitCellMapGLList.end();++pos)
3659  if((*pos)->Show()) (*pos)->Draw();
3660  glPopMatrix();
3661  }
3662  }
3663  glDepthMask(GL_TRUE);
3664  glAlphaFunc(GL_ALWAYS,1);
3665  glFlush();
3666  SwapBuffers();
3667  VFN_DEBUG_EXIT("WXGLCrystalCanvas::OnPaint():End",7)
3668 }
3669 
3670 void WXGLCrystalCanvas::OnEraseBackground(wxEraseEvent& event)
3671 {
3672 }
3673 
3674 void WXGLCrystalCanvas::OnKeyDown(wxKeyEvent& event)
3675 {
3676  VFN_DEBUG_MESSAGE("WXGLCrystalCanvas::OnKeyDown():"<<event.GetKeyCode(),2)
3677  switch(event.GetKeyCode())
3678  {
3679  case(45):// +
3680  {
3681  VFN_DEBUG_MESSAGE("WXGLCrystalCanvas::OnKeyDown():Bigger",2)
3682  int width, height;
3683  GetClientSize(& width, & height);
3684  mDist *= 1.05;
3685  SetCurrent();
3686  glMatrixMode(GL_PROJECTION);
3687  glLoadIdentity();
3688  if( (width>0)&&(height>0)) //in case size is null...
3689  gluPerspective(mViewAngle,(float)width/(float)height,
3690  (mDist>100)?(mDist-100):1.,mDist+100);
3691  Refresh(FALSE);
3692  break;
3693  }
3694  case(43):// -
3695  {
3696  VFN_DEBUG_MESSAGE("WXGLCrystalCanvas::OnKeyDown():Smaller",2)
3697  int width, height;
3698  GetClientSize(& width, & height);
3699  mDist *= .95;
3700  SetCurrent();
3701  glMatrixMode(GL_PROJECTION);
3702  glLoadIdentity();
3703  if( (width>0)&&(height>0)) //in case size is null...
3704  gluPerspective(mViewAngle,(float)width/(float)height,
3705  (mDist>100)?(mDist-100):1.,mDist+100);
3706  Refresh(FALSE);
3707  break;
3708  }
3709  case(WXK_INSERT): mY0 += 0.1; Refresh(FALSE); break;
3710  case(WXK_DELETE): mY0 -= 0.1; Refresh(FALSE); break;
3711  case(WXK_HOME): mX0 -= 0.1; Refresh(FALSE); break;
3712  case(WXK_END): mX0 += 0.1; Refresh(FALSE); break;
3713  case(WXK_PAGEUP): mZ0 -= 0.1; Refresh(FALSE); break;
3714  case(WXK_PAGEDOWN): mZ0 += 0.1; Refresh(FALSE); break;
3715  case(52):// 4
3716  {
3717  VFN_DEBUG_MESSAGE("WXGLCrystalCanvas::OnKeyDown():rotate left",2)
3718  float spin_quat[4];
3719  trackball(spin_quat,0,0,-.05,0);
3720  add_quats( spin_quat, mQuat, mQuat );
3721  Refresh(FALSE);
3722  break;
3723  }
3724  case(54):// 6
3725  {
3726  VFN_DEBUG_MESSAGE("WXGLCrystalCanvas::OnKeyDown():rotate right",2)
3727  float spin_quat[4];
3728  trackball(spin_quat,0,0,.05,0);
3729  add_quats( spin_quat, mQuat, mQuat );
3730  Refresh(FALSE);
3731  break;
3732  }
3733  case(50):// 2
3734  {
3735  VFN_DEBUG_MESSAGE("WXGLCrystalCanvas::OnKeyDown():rotate down",2)
3736  float spin_quat[4];
3737  trackball(spin_quat,0,0,0,-.05);
3738  add_quats( spin_quat, mQuat, mQuat );
3739  Refresh(FALSE);
3740  break;
3741  }
3742  case(56):// 8
3743  {
3744  VFN_DEBUG_MESSAGE("WXGLCrystalCanvas::OnKeyDown():rotate up",2)
3745  float spin_quat[4];
3746  trackball(spin_quat,0,0,0,.05);
3747  add_quats( spin_quat, mQuat, mQuat );
3748  Refresh(FALSE);
3749  break;
3750  }
3751  case(68):// D
3752  {
3753  VFN_DEBUG_MESSAGE("WXGLCrystalCanvas::OnKeyDown():rotate left",2)
3754  float spin_quat[4];
3755  trackball(spin_quat,0,0,-.05,0);
3756  add_quats( spin_quat, mQuat, mQuat );
3757  Refresh(FALSE);
3758  break;
3759  }
3760  case(70):// F
3761  {
3762  VFN_DEBUG_MESSAGE("WXGLCrystalCanvas::OnKeyDown():rotate right",2)
3763  float spin_quat[4];
3764  trackball(spin_quat,0,0,.05,0);
3765  add_quats( spin_quat, mQuat, mQuat );
3766  Refresh(FALSE);
3767  break;
3768  }
3769  case(67):// C
3770  {
3771  VFN_DEBUG_MESSAGE("WXGLCrystalCanvas::OnKeyDown():rotate down",2)
3772  float spin_quat[4];
3773  trackball(spin_quat,0,0,0,-.05);
3774  add_quats( spin_quat, mQuat, mQuat );
3775  Refresh(FALSE);
3776  break;
3777  }
3778  case(66):// B
3779  {
3780  VFN_DEBUG_MESSAGE("WXGLCrystalCanvas::OnKeyDown():toggle black/white background",2)
3781  mWhiteBackground = !mWhiteBackground;
3782  Refresh(FALSE);
3783  break;
3784  }
3785  case(82):// R
3786  {
3787  VFN_DEBUG_MESSAGE("WXGLCrystalCanvas::OnKeyDown():rotate up",2)
3788  float spin_quat[4];
3789  trackball(spin_quat,0,0,0,.05);
3790  add_quats( spin_quat, mQuat, mQuat );
3791  Refresh(FALSE);
3792  break;
3793  }
3794  case(72):// H
3795  {
3796  VFN_DEBUG_MESSAGE("WXGLCrystalCanvas::OnKeyDown():toggle help",2)
3797  mShowHelp = !mShowHelp;
3798  Refresh(FALSE);
3799  break;
3800  }
3801  case(76):// L
3802  {
3803  VFN_DEBUG_MESSAGE("WXGLCrystalCanvas::OnKeyDown():toggle atom labels",2)
3804  mShowAtomName = !mShowAtomName;
3805  Refresh(FALSE);
3806  break;
3807  }
3808  case(77):// M
3809  {
3810  mShowFullMolecule = !mShowFullMolecule;
3811  wxConfigBase::Get()->Write(_T("Crystal/BOOL/Show full molecules in 3D view"), mShowFullMolecule);
3812  VFN_DEBUG_MESSAGE("WXGLCrystalCanvas::OnKeyDown():toggle showing full molecules: "<<mShowFullMolecule,2)
3813 
3814  // Should be done with an event ?
3815  if(!(mpWXCrystal->GetCrystal().IsBeingRefined()))
3816  mpWXCrystal->UpdateGL(false,
3817  mcellbbox.xMin,mcellbbox.xMax,
3818  mcellbbox.yMin,mcellbbox.yMax,
3819  mcellbbox.zMin,mcellbbox.zMax, mFadeDistance, mShowFullMolecule);
3820  break;
3821  }
3822  case(89):// y
3823  {
3824  mShowHydrogens = !mShowHydrogens;
3825  // Should be done with an event ?
3826  if(!(mpWXCrystal->GetCrystal().IsBeingRefined()))
3827  mpWXCrystal->UpdateGL(false,
3828  mcellbbox.xMin,mcellbbox.xMax,
3829  mcellbbox.yMin,mcellbbox.yMax,
3830  mcellbbox.zMin,mcellbbox.zMax, mFadeDistance, mShowFullMolecule);
3831  break;
3832  }
3833  case(WXK_F1):
3834  {
3835  VFN_DEBUG_MESSAGE("WXGLCrystalCanvas::OnKeyDown():F1",2)
3836  if(event.ShiftDown())
3837  {
3838  mcellbbox.xMin -= 0.05;
3839  mcellbbox.xMax -= 0.05;
3840  }
3841  else
3842  {
3843  if((mcellbbox.xMax-mcellbbox.xMin)>0.1)
3844  {
3845  mcellbbox.xMin += 0.05;
3846  mcellbbox.xMax -= 0.05;
3847  }
3848  }
3849  break;
3850  }
3851  case(WXK_F2):
3852  {
3853  VFN_DEBUG_MESSAGE("WXGLCrystalCanvas::OnKeyDown():F2",2)
3854  if(event.ShiftDown())
3855  {
3856  mcellbbox.xMin += 0.05;
3857  mcellbbox.xMax += 0.05;
3858  }
3859  else
3860  {
3861  mcellbbox.xMin -= 0.05;
3862  mcellbbox.xMax += 0.05;
3863  }
3864  break;
3865  }
3866  case(WXK_F3):
3867  {
3868  VFN_DEBUG_MESSAGE("WXGLCrystalCanvas::OnKeyDown():F3",2)
3869  if(event.ShiftDown())
3870  {
3871  mcellbbox.yMin -= 0.05;
3872  mcellbbox.yMax -= 0.05;
3873  }
3874  else
3875  {
3876  if((mcellbbox.yMax-mcellbbox.yMin)>0.1)
3877  {
3878  mcellbbox.yMin += 0.05;
3879  mcellbbox.yMax -= 0.05;
3880  }
3881  }
3882  break;
3883  }
3884  case(WXK_F4):
3885  {
3886  VFN_DEBUG_MESSAGE("WXGLCrystalCanvas::OnKeyDown():F4",2)
3887  if(event.ShiftDown())
3888  {
3889  mcellbbox.yMin += 0.05;
3890  mcellbbox.yMax += 0.05;
3891  }
3892  else
3893  {
3894  mcellbbox.yMin -= 0.05;
3895  mcellbbox.yMax += 0.05;
3896  }
3897  break;
3898  }
3899  case(WXK_F5):
3900  {
3901  VFN_DEBUG_MESSAGE("WXGLCrystalCanvas::OnKeyDown():F5",2)
3902  if(event.ShiftDown())
3903  {
3904  mcellbbox.zMin -= 0.05;
3905  mcellbbox.zMax -= 0.05;
3906  }
3907  else
3908  {
3909  if((mcellbbox.zMax-mcellbbox.zMin)>0.1)
3910  {
3911  mcellbbox.zMin += 0.05;
3912  mcellbbox.zMax -= 0.05;
3913  }
3914  }
3915  break;
3916  }
3917  case(WXK_F6):
3918  {
3919  VFN_DEBUG_MESSAGE("WXGLCrystalCanvas::OnKeyDown():F6",2)
3920  if(event.ShiftDown())
3921  {
3922  mcellbbox.zMin += 0.05;
3923  mcellbbox.zMax += 0.05;
3924  }
3925  else
3926  {
3927  mcellbbox.zMin -= 0.05;
3928  mcellbbox.zMax += 0.05;
3929  }
3930  break;
3931  }
3932  case(WXK_F7):
3933  {
3934  VFN_DEBUG_MESSAGE("WXGLCrystalCanvas::OnKeyDown():F5",2)
3935  mFadeDistance -=0.5;
3936  if(mFadeDistance<0)
3937  {
3938  mFadeDistance=0;
3939  }
3940  break;
3941  }
3942  case(WXK_F8):
3943  {
3944  VFN_DEBUG_MESSAGE("WXGLCrystalCanvas::OnKeyDown():F6",2)
3945  mFadeDistance+=0.5;
3946  break;
3947  }
3948  case(WXK_F9):
3949  {
3950  VFN_DEBUG_MESSAGE("WXGLCrystalCanvas::OnKeyDown():F9",2)
3951  mcellbbox.xMin = mpWXCrystal->GetCrystal().GetSpaceGroup().GetAsymUnit().Xmin();
3952  mcellbbox.yMin = mpWXCrystal->GetCrystal().GetSpaceGroup().GetAsymUnit().Ymin();
3953  mcellbbox.zMin = mpWXCrystal->GetCrystal().GetSpaceGroup().GetAsymUnit().Zmin();
3954  mcellbbox.xMax = mpWXCrystal->GetCrystal().GetSpaceGroup().GetAsymUnit().Xmax();
3955  mcellbbox.yMax = mpWXCrystal->GetCrystal().GetSpaceGroup().GetAsymUnit().Ymax();
3956  mcellbbox.zMax = mpWXCrystal->GetCrystal().GetSpaceGroup().GetAsymUnit().Zmax();
3957  break;
3958  }
3959  case(WXK_F10):
3960  {
3961  VFN_DEBUG_MESSAGE("WXGLCrystalCanvas::OnKeyDown():F10",2)
3962  mcellbbox.xMin = 0;
3963  mcellbbox.yMin = 0;
3964  mcellbbox.zMin = 0;
3965  mcellbbox.xMax = 1;
3966  mcellbbox.yMax = 1;
3967  mcellbbox.zMax = 1;
3968  break;
3969  }
3970  default:
3971  {
3972  cout<<"WXGLCrystalCanvas::OnKeyDown(): Unknown KeyCode: "<<event.GetKeyCode()<<endl;
3973  event.Skip();
3974  }
3975  }
3976  if( (event.GetKeyCode()==WXK_F1)||(event.GetKeyCode()==WXK_F2)||(event.GetKeyCode()==WXK_F3)||(event.GetKeyCode()==WXK_F4)
3977  ||(event.GetKeyCode()==WXK_F5)||(event.GetKeyCode()==WXK_F6)||(event.GetKeyCode()==WXK_F7)||(event.GetKeyCode()==WXK_F8)
3978  ||(event.GetKeyCode()==WXK_F9)||(event.GetKeyCode()==WXK_F10))
3979  {
3980  if(!(mpWXCrystal->GetCrystal().IsBeingRefined()))
3981  mpWXCrystal->UpdateGL(false,
3982  mcellbbox.xMin,mcellbbox.xMax,
3983  mcellbbox.yMin,mcellbbox.yMax,
3984  mcellbbox.zMin,mcellbbox.zMax, mFadeDistance, mShowFullMolecule);
3985  }
3986 }
3987 
3988 void WXGLCrystalCanvas::OnKeyUp(wxKeyEvent& event)
3989 {
3990  VFN_DEBUG_MESSAGE("WXGLCrystalCanvas::OnKeyUp():"<<event.GetKeyCode(),2)
3991 }
3992 
3993 void WXGLCrystalCanvas::OnEnterWindow( wxMouseEvent& event )
3994 {
3995  VFN_DEBUG_MESSAGE("WXGLCrystalCanvas::OnEnterWindow()",5)
3996 }
3997 
3998 void WXGLCrystalCanvas::OnMouse( wxMouseEvent& event )
3999 {
4000  if(event.Leaving()) return;// wxMSW2.4 bug ?
4001  VFN_DEBUG_MESSAGE("WXGLCrystalCanvas::OnMouse()"
4002  <<endl<<"IsButton():"<<event.IsButton()
4003  <<endl<<"ButtonDown():"<<event.ButtonDown()
4004  <<endl<<"Dragging():"<<event.Dragging()
4005  <<endl<<"Entering():"<<event.Entering()
4006  <<endl<<"Leaving():"<<event.Leaving()
4007  <<endl<<"GetButton()"<<event.GetButton()
4008  <<endl<<"GetWheelAxis():"<<event.GetWheelAxis()
4009  <<endl<<"GetWheelDelta():"<<event.GetWheelDelta()
4010  <<endl<<"GetWheelRotation():"<<event.GetWheelRotation()
4011  <<endl<<"Moving():"<<event.Moving()
4012  <<endl,7)
4013  if (event.Dragging())
4014  {
4015  int width, height;
4016  GetClientSize(& width, & height);
4017  if(event.LeftIsDown())
4018  {
4019  if(event.ShiftDown())
4020  {
4021  VFN_DEBUG_MESSAGE("WXGLCrystalCanvas::OnMouse():Dragging Left Button",2)
4022 
4023  REAL vx1=mTrackBallLastX,vy1=mTrackBallLastY,vz1,
4024  vx2=event.GetX(), vy2=event.GetY(), vz2;
4025 
4026  this->UnProject(vx1,vy1,vz1);
4027  this->UnProject(vx2,vy2,vz2);
4028 
4029  mX0 += vx2-vx1;
4030  mY0 += vy2-vy1;
4031  mZ0 += vz2-vz1;
4032 
4033  VFN_DEBUG_MESSAGE("Origin (ortho) = "<<mX0<<", "<<mY0<<", "<<mZ0,2)
4034  Refresh(FALSE);
4035  }
4036  else
4037  {
4038  VFN_DEBUG_MESSAGE("WXGLCrystalCanvas::OnMouse():Dragging Left Button",2)
4039  // drag in progress, simulate trackball
4040  float spin_quat[4];
4041  trackball(spin_quat,
4042  (2.0*mTrackBallLastX - width) / (width+.001), //normalizing from -1 to 1
4043  ( height - 2.0*mTrackBallLastY) / (height+.001),
4044  ( 2.0*event.GetX() - width) / (width+.001),
4045  ( height - 2.0*event.GetY()) / (height+.001));
4046 
4047  add_quats( spin_quat, mQuat, mQuat );
4048  Refresh(FALSE);
4049  }
4050  }
4051  if(event.MiddleIsDown())
4052  {
4053  VFN_DEBUG_MESSAGE("WXGLCrystalCanvas::OnMouse():Dragging Middle Button",2)
4054  const float v= (mTrackBallLastY-event.GetY())/(float)height;
4055  const float h= (mTrackBallLastX-event.GetX())/(float)width;
4056 
4057  mDist *= (1.+v)/(1.+h);
4058  mViewAngle *=(1.+h);
4059  SetCurrent();
4060  glMatrixMode(GL_PROJECTION);
4061  glLoadIdentity();
4062  if( (width>0)&&(height>0)) //in case size is null...
4063  gluPerspective(mViewAngle,(float)width/(float)height,
4064  (mDist>101)?(mDist-100):1.,mDist+100);
4065  Refresh(FALSE);
4066  VFN_DEBUG_MESSAGE(mViewAngle <<" "<<mDist,2)
4067  }
4068  }
4069  //else if(event.Leaving()) cout<<"Mouse is leaving window!!"<<endl;
4070  else if(event.RightIsDown())
4071  {
4072  VFN_DEBUG_MESSAGE("WXGLCrystalCanvas::OnMouse():Right Button",2)
4073  if(mpWXCrystal->GetCrystal().IsBeingRefined())
4074  {
4075  mpPopUpMenu->Enable(ID_GLCRYSTAL_MENU_UPDATE, false);
4076  mpPopUpMenu->Enable(ID_GLCRYSTAL_MENU_POVRAY, false);
4077  mpPopUpMenu->Enable(ID_GLCRYSTAL_MENU_LOADFOURIERGRD, false);
4078  mpPopUpMenu->Enable(ID_GLCRYSTAL_MENU_LOADFOURIERDSN6, false);
4079  }
4080  else
4081  {
4082  mpPopUpMenu->Enable(ID_GLCRYSTAL_MENU_UPDATE, true);
4083  mpPopUpMenu->Enable(ID_GLCRYSTAL_MENU_POVRAY, true);
4084  mpPopUpMenu->Enable(ID_GLCRYSTAL_MENU_LOADFOURIERGRD, true);
4085  mpPopUpMenu->Enable(ID_GLCRYSTAL_MENU_LOADFOURIERDSN6, true);
4086  }
4087 
4088  this->PopupMenu(mpPopUpMenu, event.GetX(), event.GetY() );
4089  }
4090  else if (event.GetWheelDelta()>0)
4091  {// Double-touch event on OSX + trackpad
4092  if(event.ControlDown())
4093  {
4094  VFN_DEBUG_MESSAGE("WXGLCrystalCanvas::OnMouse(): Mouse Wheel / double touch + control (OSX: command)",2)
4095  //Change zoom / angle
4096  int width, height;
4097  GetClientSize(& width, & height);
4098  const int delta=event.GetWheelDelta();
4099  const int rotation=event.GetWheelRotation();
4100 
4101  if(event.GetWheelAxis()==0) mDist *= (1.+float(rotation)/100.);
4102  else
4103  {
4104  mDist /= (1.+float(rotation)/100.);
4105  mViewAngle *=(1.+float(rotation)/100.);
4106  }
4107  SetCurrent();
4108  glMatrixMode(GL_PROJECTION);
4109  glLoadIdentity();
4110  if( (width>0)&&(height>0)) //in case size is null...
4111  gluPerspective(mViewAngle,(float)width/(float)height,
4112  (mDist>101)?(mDist-100):1.,mDist+100);
4113  Refresh(FALSE);
4114  VFN_DEBUG_MESSAGE(mViewAngle <<" "<<mDist,2)
4115  }
4116  else
4117  {
4118  VFN_DEBUG_MESSAGE("WXGLCrystalCanvas::OnMouse(): Mouse Wheel / double touch",2)
4119  // Rotate view with trackball
4120  int width, height;
4121  GetClientSize(& width, & height);
4122  const int delta=event.GetWheelDelta();
4123  int dx=0,dy=0;
4124  if(event.GetWheelAxis()==1) dx=-event.GetWheelRotation();
4125  else dy=event.GetWheelRotation();
4126  float spin_quat[4];
4127  trackball(spin_quat,
4128  (2.0*mTrackBallLastX - width) / (width+.001), //normalizing from -1 to 1
4129  ( height - 2.0*mTrackBallLastY) / (height+.001),
4130  (2.0*(mTrackBallLastX+dx) - width) / (width+.001),
4131  ( height - 2.0*(mTrackBallLastY+dy)) / (height+.001));
4132 
4133  add_quats( spin_quat, mQuat, mQuat );
4134  Refresh(FALSE);
4135  }
4136  }
4137 
4138  mTrackBallLastX = event.GetX();
4139  mTrackBallLastY = event.GetY();
4140  event.Skip();
4141 }
4142 
4143 void WXGLCrystalCanvas::OnUpdate(wxCommandEvent & WXUNUSED(event))
4144 {
4145  VFN_DEBUG_ENTRY("WXGLCrystalCanvas::OnUpdate()",4)
4146  mpWXCrystal->UpdateGL(false,
4147  mcellbbox.xMin,mcellbbox.xMax,
4148  mcellbbox.yMin,mcellbbox.yMax,
4149  mcellbbox.zMin,mcellbbox.zMax, mFadeDistance, mShowFullMolecule);
4150  VFN_DEBUG_EXIT("WXGLCrystalCanvas::OnUpdate()",4)
4151 }
4152 
4153 void WXGLCrystalCanvas::CrystUpdate()
4154 {
4155  // This can only be called from the main (graphical) thread
4156  VFN_DEBUG_ENTRY("WXGLCrystalCanvas::CrystUpdate():"<<wxThread::IsMain(),10)
4157  // Update the list of available maps & update the displayed ones
4158  if(mpFourierMapListWin!=0) mpFourierMapListWin->mMutex.Lock();
4159  // Remove maps that cannot be computed any more
4160  for(vector<boost::shared_ptr<UnitCellMap> >::iterator pos=mvpUnitCellMap.begin();pos!=mvpUnitCellMap.end();)
4161  {
4162  bool keep=false;
4163  if((*pos)->GetType()==3) keep=true;
4164  if(((*pos)->GetType()==0)||((*pos)->GetType()==2))
4165  {
4166  /*
4167  cout<<"WXGLCrystalCanvas::CrystUpdate()"<<endl<<(*pos)->GetName()<<(*pos)->GetType()<<" "
4168  <<mpWXCrystal->GetCrystal().GetScatteringComponentList().GetNbComponent()<<","
4169  <<(*pos)->GetData()->GetFhklObsSq().numElements()<<endl;
4170  */
4171  if(mpWXCrystal->GetCrystal().GetClientRegistry().Find((RefinableObj*)(*pos)->GetData())>=0)
4172  if(mpWXCrystal->GetCrystal().GetScatteringComponentList().GetNbComponent()>0)
4173  if((*pos)->GetData()->GetFhklObsSq().numElements()>0)
4174  keep=true;
4175  }
4176  if((*pos)->GetType()==1)
4177  {
4178  if(mpWXCrystal->GetCrystal().GetClientRegistry().Find((RefinableObj*)(*pos)->GetData())>=0)
4179  if(mpWXCrystal->GetCrystal().GetScatteringComponentList().GetNbComponent()>0)
4180  keep=true;
4181  }
4182  VFN_DEBUG_MESSAGE("WXGLCrystalCanvas::CrystUpdate()"<<(*pos)->GetName()<<(*pos)->GetType()<<": keep="<<keep,8)
4183  if(!keep)
4184  {
4185  //erase corresponding gl maps
4186  for(vector<boost::shared_ptr<UnitCellMapGLList> >::iterator
4187  posgl=mvpUnitCellMapGLList.begin();posgl!=mvpUnitCellMapGLList.end();)
4188  {
4189  if(&(**pos)==&((*posgl)->GetMap()))
4190  {
4191  VFN_DEBUG_MESSAGE("Erasing GL map:"<<(*posgl)->GetName(),8)
4192  posgl=mvpUnitCellMapGLList.erase(posgl);
4193  } else ++posgl;
4194  }
4195  pos=mvpUnitCellMap.erase(pos);
4196  }
4197  else
4198  {
4199  if((*pos)->GetType()!=3)
4200  {
4201  #ifdef HAVE_FFTW
4202  // During optimization, only update Fourier maps if one is displayed or the Fourier win is opened
4203  if( (mvpUnitCellMapGLList.size()>0)
4204  ||(!(mpWXCrystal->GetCrystal().IsBeingRefined()))
4205  ||(mpFourierMapListWin!=0))
4206  (*pos)->CalcFourierMap(*((*pos)->GetData()),(*pos)->GetType(),mSharpenMap);
4207  #endif
4208  }
4209  ++pos;
4210  }
4211  }
4212  #ifdef HAVE_FFTW
4213  // Add newly computable maps
4214  if(mpWXCrystal->GetCrystal().GetScatteringComponentList().GetNbComponent()>0)
4215  for(int i=0;i<mpWXCrystal->GetCrystal().GetClientRegistry().GetNb();++i)
4216  {
4217  ScatteringData* data=dynamic_cast<ScatteringData *>(&(mpWXCrystal->GetCrystal().GetClientRegistry().GetObj(i)));
4218 
4219  if(data!=0)
4220  {
4221  // Add if not already listed
4222  bool addCalcMap=true,addObsDiffMaps=true;
4223  for(vector<boost::shared_ptr<UnitCellMap> >::iterator pos=mvpUnitCellMap.begin();pos!=mvpUnitCellMap.end();++pos)
4224  if((*pos)->GetData()==data)
4225  {
4226  if((*pos)->GetType()==1) addCalcMap=false;
4227  if((*pos)->GetType()==0) addObsDiffMaps=false;//type==2 will also be there
4228  }
4229  //cout<<__FILE__<<":"<<__LINE__<<":WXGLCrystalCanvas::CrystUpdate()"
4230  // <<data<<","<<addCalcMap<<","<<addObsDiffMaps<<endl;
4231  if(addCalcMap&&(data->GetNbRefl()>0))
4232  {
4233  mvpUnitCellMap.push_back(boost::shared_ptr<UnitCellMap>(new UnitCellMap(mpWXCrystal->GetCrystal())));
4234  mvpUnitCellMap.back()->CalcFourierMap(*data,1);
4235  VFN_DEBUG_MESSAGE("Added GL map:"<<mvpUnitCellMap.back()->GetName(),8)
4236  }
4237  if(addObsDiffMaps && (data->GetFhklObsSq().numElements()>0) )
4238  {
4239  mvpUnitCellMap.push_back(boost::shared_ptr<UnitCellMap>(new UnitCellMap(mpWXCrystal->GetCrystal())));
4240  mvpUnitCellMap.back()->CalcFourierMap(*data,0);
4241  VFN_DEBUG_MESSAGE("Added GL map:"<<mvpUnitCellMap.back()->GetName()<<":"<<data->GetFhklObsSq().numElements(),8)
4242  mvpUnitCellMap.push_back(boost::shared_ptr<UnitCellMap>(new UnitCellMap(mpWXCrystal->GetCrystal())));
4243  mvpUnitCellMap.back()->CalcFourierMap(*data,2);
4244  VFN_DEBUG_MESSAGE("Added GL map:"<<mvpUnitCellMap.back()->GetName()<<":"<<data->GetFhklObsSq().numElements(),8)
4245  }
4246  }
4247  }
4248  #endif
4249  //update GL maps
4250  for(vector<boost::shared_ptr<UnitCellMapGLList> >::iterator
4251  pos=mvpUnitCellMapGLList.begin();pos!=mvpUnitCellMapGLList.end();++pos)
4252  {
4253  //cout<<"Updating GL map:"<<(*pos)->GetName()<<endl;
4254  (*pos)->GenList();
4255  }
4256  if(mpFourierMapListWin!=0) mpFourierMapListWin->mMutex.Unlock();
4257  VFN_DEBUG_EXIT("WXGLCrystalCanvas::CrystUpdate()",10)
4258 
4259  wxUpdateUIEvent event(ID_GLCRYSTAL_UPDATEUI);
4260  wxPostEvent(this,event);
4261  /* // To make a movie
4262  if(mpWXCrystal->GetCrystal().IsBeingRefined())
4263  {
4264  // Export POV-Ray file to make a movie
4265  char povFile[40];
4266  time_t date=time(0);
4267  strftime(povFile,sizeof(povFile),"pov/%Y%m%d-%Hh%Mm%Ss%Z.pov",gmtime(&date));//%Y-%m-%dT%H:%M:%S%Z
4268  this->POVRayOutput(povFile);
4269  }
4270  */
4271 }
4272 
4273 void WXGLCrystalCanvas::OnUpdateUI(wxUpdateUIEvent&event)
4274 {
4275  VFN_DEBUG_ENTRY("WXGLCrystalCanvas::OnUpdateUI()",5)
4276  if(mpFourierMapListWin!=0)
4277  {
4278  mpFourierMapListWin->mIsUpdating=true;
4279  mpFourierMapListWin->mMutex.Lock();
4280 
4281  wxArrayString maps;
4282  for(vector<boost::shared_ptr<UnitCellMap> >::iterator
4283  pos=mvpUnitCellMap.begin();pos!=mvpUnitCellMap.end();++pos)
4284  maps.Add( wxString::FromAscii((*pos)->GetName().c_str()));
4285  if(mpFourierMapListWin->mpAvailableMapList->GetStrings()!=maps)
4286  mpFourierMapListWin->mpAvailableMapList->Set(maps);
4287 
4288  wxArrayString glmaps;
4289  for(vector<boost::shared_ptr<UnitCellMapGLList> >::iterator
4290  pos=mvpUnitCellMapGLList.begin();pos!=mvpUnitCellMapGLList.end();++pos)
4291  glmaps.Add( wxString::FromAscii((*pos)->GetName().c_str()));
4292  if(mpFourierMapListWin->mpDisplayedMapList->GetStrings()!=glmaps)
4293  mpFourierMapListWin->mpDisplayedMapList->Set(glmaps);
4294 
4295  if(mpFourierMapListWin->mpAvailableMapList->GetSelection()>=0)
4296  {
4297  boost::shared_ptr<ObjCryst::UnitCellMap> pMap=mvpUnitCellMap[mpFourierMapListWin->mpAvailableMapList->GetSelection()];
4298  mpFourierMapListWin->mpMapInfo->SetLabel(wxString::Format(_T("min=%5.2f max=%5.2f sigma=%5.2f"),
4299  pMap->Min(),pMap->Max(),pMap->StandardDeviation()));
4300  }
4301  mpFourierMapListWin->mMutex.Unlock();
4302  mpFourierMapListWin->mIsUpdating=false;
4303  }
4304  this->Refresh(false);
4305  event.Skip();
4306  VFN_DEBUG_EXIT("WXGLCrystalCanvas::OnUpdateUI()",5)
4307 }
4308 
4309 void WXGLCrystalCanvas::SetCurrent()
4310 {
4311  VFN_DEBUG_ENTRY("WXGLCrystalCanvas::SetCurrent()",4)
4312  this->wxGLCanvas::SetCurrent(*mpwxGLContext);
4313  #ifndef HAVE_GLUT
4314  this->BuildGLFont();
4315  sFontDisplayListBase=mGLFontDisplayListBase;
4316  #endif
4317  VFN_DEBUG_EXIT("WXGLCrystalCanvas::SetCurrent()",4)
4318 }
4319 
4320 void WXGLCrystalCanvas::NotifyDeleteFourierWin()
4321 {
4322  mpFourierMapListWin=0;
4323 }
4324 
4325 void WXGLCrystalCanvas::InitGL()
4326 {
4327  // This is called once, when the window is actually displayed
4328  wxCommandEvent event(wxEVT_COMMAND_MENU_SELECTED,ID_GLCRYSTAL_MENU_UPDATE);
4329  wxPostEvent(this,event);
4330 
4331  VFN_DEBUG_ENTRY("WXGLCrystalCanvas::InitGL()",8)
4332  this->SetCurrent();
4333  #ifdef HAVE_GLUT
4334  static bool needglutinit=true;
4335  if(needglutinit)
4336  {
4337  needglutinit=false;
4338  //glutInit(&(wxApp::GetInstance()->argc),wxApp::GetInstance()->argv);
4339  char **argv=new char*;
4340  int argc=0;
4341  glutInit(&argc,argv);// We cannot pass arguments directly in Unicode mode, so...
4342  }
4343  #endif
4344 
4345  int width, height;
4346  GetClientSize(& width, & height);
4347  glViewport(0, 0, width, height);
4348 
4349  glEnable(GL_DEPTH_TEST);
4350  glEnable(GL_ALPHA_TEST);
4351  glEnable(GL_LIGHTING);
4352  glEnable (GL_BLEND);
4353  glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
4354 
4355  const GLfloat colour_Ambient [] = {0.4, 0.4, 0.4, 1.00};
4356  const GLfloat colour_Diffuse [] = {0.6, 0.6, 0.6, 1.00};
4357  const GLfloat colour_Specular[] = {0.2, 0.2, 0.2, 1.00};
4358 
4359  glLightModelf(GL_LIGHT_MODEL_TWO_SIDE, 1.0);
4360 
4361  const GLfloat LightPosition[]= { -10.0f, 10.0f, 10.0f, 0.0f };
4362  glLightfv(GL_LIGHT1, GL_AMBIENT, colour_Ambient);
4363  glLightfv(GL_LIGHT1, GL_DIFFUSE, colour_Diffuse);
4364  glLightfv(GL_LIGHT1, GL_SPECULAR, colour_Specular);
4365  glLightfv(GL_LIGHT1, GL_SHININESS,colour_Specular);
4366  glLightfv(GL_LIGHT1, GL_POSITION,LightPosition);
4367  glEnable(GL_LIGHT1);
4368 
4369  glEnable(GL_NORMALIZE);
4370  glHint(GL_PERSPECTIVE_CORRECTION_HINT,GL_NICEST);//GL_FASTEST
4371  glHint(GL_POLYGON_SMOOTH_HINT,GL_NICEST);//GL_FASTEST
4372 
4373  if(sGLCrystalConfig.mSaved==false)
4374  {
4375  //Initialize Trackball
4376  trackball(mQuat,0.,0.,0.,0.);
4377  }
4378  wxSizeEvent ev;
4379  wxPostEvent(this,ev);
4380 
4381  //First display
4382  this->CrystUpdate();
4383  VFN_DEBUG_EXIT("WXGLCrystalCanvas::InitGL()",8)
4384 }
4385 void WXGLCrystalCanvas::OnChangeLimits(wxCommandEvent &event)
4386 {
4387  VFN_DEBUG_MESSAGE("WXGLCrystalCanvas::OnChangeLimits()",10)
4388  if(event.GetId()==ID_GLCRYSTAL_MENU_LIMITS_FULLCELL)
4389  {
4390  mcellbbox.xMin = 0;
4391  mcellbbox.yMin = 0;
4392  mcellbbox.zMin = 0;
4393  mcellbbox.xMax = 1;
4394  mcellbbox.yMax = 1;
4395  mcellbbox.zMax = 1;
4396  vector<boost::shared_ptr<UnitCellMapGLList> >::iterator pos;
4397  for(pos=mvpUnitCellMapGLList.begin();pos != mvpUnitCellMapGLList.end();pos++)
4398  {
4399  wxBusyInfo wait(_T("Processing Fourier Map..."));
4400  (*pos)->GenList();
4401  }
4402  }
4403  if(event.GetId()==ID_GLCRYSTAL_MENU_LIMITS_ASYMCELL)
4404  {
4405  mcellbbox.xMin = mpWXCrystal->GetCrystal().GetSpaceGroup().GetAsymUnit().Xmin();
4406  mcellbbox.yMin = mpWXCrystal->GetCrystal().GetSpaceGroup().GetAsymUnit().Ymin();
4407  mcellbbox.zMin = mpWXCrystal->GetCrystal().GetSpaceGroup().GetAsymUnit().Zmin();
4408  mcellbbox.xMax = mpWXCrystal->GetCrystal().GetSpaceGroup().GetAsymUnit().Xmax();
4409  mcellbbox.yMax = mpWXCrystal->GetCrystal().GetSpaceGroup().GetAsymUnit().Ymax();
4410  mcellbbox.zMax = mpWXCrystal->GetCrystal().GetSpaceGroup().GetAsymUnit().Zmax();
4411  vector<boost::shared_ptr<UnitCellMapGLList> >::iterator pos;
4412  for(pos=mvpUnitCellMapGLList.begin();pos != mvpUnitCellMapGLList.end();pos++)
4413  {
4414  wxBusyInfo wait(_T("Processing Fourier Map..."));
4415  (*pos)->GenList();
4416  }
4417  }
4418  if(event.GetId()==ID_GLCRYSTAL_MENU_CHANGELIMITS)
4419  {
4420  UserSelectBoundingBox *BoxDlg = new UserSelectBoundingBox(this,
4421  "Set bounding box for display of\natoms (fractional coordinates)",
4422  mcellbbox);
4423  if (BoxDlg->ShowModal() == wxID_OK )
4424  {
4425  mcellbbox = BoxDlg->GetBBox();
4426  mpWXCrystal->UpdateGL(false,
4427  mcellbbox.xMin,mcellbbox.xMax,
4428  mcellbbox.yMin,mcellbbox.yMax,
4429  mcellbbox.zMin,mcellbbox.zMax, mFadeDistance, mShowFullMolecule);
4430  vector<boost::shared_ptr<UnitCellMapGLList> >::iterator pos;
4431  for(pos=mvpUnitCellMapGLList.begin();pos != mvpUnitCellMapGLList.end();pos++)
4432  {
4433  wxBusyInfo wait(_T("Processing Fourier Map..."));
4434  (*pos)->GenList();
4435  }
4436  VFN_DEBUG_MESSAGE("WXGLCrystalCanvas::OnChangeLimits (X: " <<
4437  mcellbbox.xMin << ", " << mcellbbox.xMax <<
4438  " Y: " <<
4439  mcellbbox.yMin << ", " << mcellbbox.yMax <<
4440  " Z: " <<
4441  mcellbbox.zMin << ", " << mcellbbox.zMax <<
4442  ")", 10)
4443  }
4444  BoxDlg->Destroy();
4445  }
4446  if(!(mpWXCrystal->GetCrystal().IsBeingRefined()))
4447  mpWXCrystal->UpdateGL(false,
4448  mcellbbox.xMin,mcellbbox.xMax,
4449  mcellbbox.yMin,mcellbbox.yMax,
4450  mcellbbox.zMin,mcellbbox.zMax, mFadeDistance, mShowFullMolecule);
4451 
4452  VFN_DEBUG_MESSAGE("WXGLCrystalCanvas::OnChangeLimits():UserSelectBoundingBox done",10)
4453 }
4454 
4455 void WXGLCrystalCanvas::OnShowCrystal( wxCommandEvent & WXUNUSED(event))
4456 {
4457  if(mShowCrystal) mpPopUpMenu->SetLabel(ID_GLCRYSTAL_MENU_SHOWCRYSTAL, _T("Show Crystal"));
4458  else mpPopUpMenu->SetLabel(ID_GLCRYSTAL_MENU_SHOWCRYSTAL, _T("Hide Crystal"));
4459  mShowCrystal = !mShowCrystal;
4460  if(!(mpWXCrystal->GetCrystal().IsBeingRefined())) this->CrystUpdate();
4461 }
4462 
4463 void WXGLCrystalCanvas::OnShowAtomLabel( wxCommandEvent & WXUNUSED(event))
4464 {
4465  if(mShowAtomName) mpPopUpMenu->SetLabel(ID_GLCRYSTAL_MENU_SHOWATOMLABEL, _T("Show Atom Labels"));
4466  else mpPopUpMenu->SetLabel(ID_GLCRYSTAL_MENU_SHOWATOMLABEL, _T("Hide Atom Labels"));
4467  mShowAtomName= !mShowAtomName;
4468  if(!(mpWXCrystal->GetCrystal().IsBeingRefined())) this->CrystUpdate();
4469 }
4470 
4471 void WXGLCrystalCanvas::OnShowHydrogens( wxCommandEvent & WXUNUSED(event))
4472 {
4473  if(mShowHydrogens) mpPopUpMenu->SetLabel(ID_GLCRYSTAL_MENU_SHOWHYDROGENS, _T("Show Hydrogens"));
4474  else mpPopUpMenu->SetLabel(ID_GLCRYSTAL_MENU_SHOWHYDROGENS, _T("Hide Hydrogens"));
4475  mShowHydrogens= !mShowHydrogens;
4476  if(!(mpWXCrystal->GetCrystal().IsBeingRefined()))
4477  {
4478  wxCommandEvent event(wxEVT_COMMAND_MENU_SELECTED,ID_GLCRYSTAL_MENU_UPDATE);
4479  wxPostEvent(this,event);
4480  }
4481 }
4482 
4483 bool WXGLCrystalCanvas::GetShowHydrogens() const {return mShowHydrogens;}
4484 
4485 void WXGLCrystalCanvas::OnShowCursor( wxCommandEvent & WXUNUSED(event))
4486 {
4487  if(mShowCursor) mpPopUpMenu->SetLabel(ID_GLCRYSTAL_MENU_SHOWCURSOR, _T("Show Cursor"));
4488  else mpPopUpMenu->SetLabel(ID_GLCRYSTAL_MENU_SHOWCURSOR, _T("Hide Cursor"));
4489  mShowCursor= !mShowCursor;
4490  if(!(mpWXCrystal->GetCrystal().IsBeingRefined())) this->CrystUpdate();
4491 }
4492 
4493 void WXGLCrystalCanvas::OnSetCursor( wxCommandEvent & WXUNUSED(event))
4494 {
4495  VFN_DEBUG_MESSAGE("WXGLCrystalCanvas::OnSetCursor",1)
4496  REAL x=mX0;
4497  REAL y=mY0;
4498  REAL z=mZ0;
4499  mpWXCrystal->GetCrystal().OrthonormalToFractionalCoords(x,y,z);
4500 
4501  mViewCntr.x = (mcellbbox.xMax+mcellbbox.xMin)/2. - x;
4502  mViewCntr.y = (mcellbbox.yMax+mcellbbox.yMin)/2. - y;
4503  mViewCntr.z = (mcellbbox.zMax+mcellbbox.zMin)/2. - z;
4504  UserXYZBox *BoxDlg = new UserXYZBox(this,
4505  wxString("Set fractional coordinates for view\ncenter and cursor position"),
4506  mViewCntr);
4507  if (BoxDlg->ShowModal() == wxID_OK ) {
4508  mViewCntr = BoxDlg->GetXYZ();
4509  VFN_DEBUG_MESSAGE("WXGLCrystalCanvas::OnSetCursor (frac) = " <<
4510  mViewCntr.x << "," << mViewCntr.y << "," << mViewCntr.z,1)
4511  mX0 = (mcellbbox.xMax+mcellbbox.xMin)/2. - mViewCntr.x;
4512  mY0 = (mcellbbox.yMax+mcellbbox.yMin)/2. - mViewCntr.y;
4513  mZ0 = (mcellbbox.zMax+mcellbbox.zMin)/2. - mViewCntr.z;
4514  mpWXCrystal->GetCrystal().FractionalToOrthonormalCoords(mX0, mY0, mZ0);
4515  VFN_DEBUG_MESSAGE("...ortho" << mX0 << "," << mY0 << "," << mZ0,1)
4516  Refresh(FALSE);
4517  }
4518 }
4519 
4520 void WXGLCrystalCanvas::OnShowHelp(wxCommandEvent &event)
4521 {
4522  if(mShowHelp) mpPopUpMenu->SetLabel(ID_GLCRYSTAL_MENU_SHOWHELP, _T("Show Help"));
4523  else mpPopUpMenu->SetLabel(ID_GLCRYSTAL_MENU_SHOWCURSOR, _T("Hide Help"));
4524  mShowHelp= !mShowHelp;
4525  if(!(mpWXCrystal->GetCrystal().IsBeingRefined())) this->CrystUpdate();
4526 }
4527 
4528 void WXGLCrystalCanvas::OnFourier(wxCommandEvent &event)
4529 {
4530  if(event.GetId()==ID_GLCRYSTAL_MENU_FOURIER)
4531  {
4532  if(mpFourierMapListWin!=0) return;
4533  if(mpWXCrystal->GetCrystal().IsBeingRefined())
4534  {
4535  wxMessageBox(_T("The Fourier maps dialog \ncannot be opened during an optimization"), _T("Error"), wxOK, this);
4536  return;
4537  }
4538  wxFrame *frame= new wxMiniFrame(this,-1, wxString::FromAscii(("Available Fourier maps for "+mpWXCrystal->GetCrystal().GetName()).c_str()),
4539  wxDefaultPosition,wxSize(500,500),wxCLOSE_BOX|wxCAPTION|wxSYSTEM_MENU);
4540  mpFourierMapListWin=new WXFourierMapList(this,frame);
4541  mpFourierMapListWin->mpWireFrame->SetValue(true);
4542  mpFourierMapListWin->mpShowFourier->SetValue(mShowFourier);
4543  mpFourierMapListWin->mpSharpenMap->SetValue(mSharpenMap);
4544  frame->Show(true);
4545  mpWXCrystal->GetCrystal().UpdateDisplay();
4546  return;
4547  }
4548  if(mpFourierMapListWin==0) return;
4549  if(mpFourierMapListWin->mIsUpdating) return;
4550  if( (event.GetId()==ID_GLCRYSTAL_FOURIER_UPDATE)
4551  ||(event.GetId()==ID_GLCRYSTAL_FOURIER_CONTOUR))
4552  {
4553  mpFourierMapListWin->mMutex.Lock();
4554  //Changed colour or contour ?
4555  unsigned int choice=mpFourierMapListWin->mpDisplayedMapList->GetSelection();
4556  if(wxNOT_FOUND!=choice)
4557  {
4558  double contour;
4559  mpFourierMapListWin->mpContourValue->GetValue().ToDouble(&contour);
4560  wxColour col(mpFourierMapListWin->mpColourPicker->GetColour());
4561  if(abs((float)contour-mvpUnitCellMapGLList[choice]->GetContour())>.0001)
4562  {
4563  mvpUnitCellMapGLList[choice]->SetContour((float)contour);
4564  if(false==mpWXCrystal->GetCrystal().IsBeingRefined())
4565  {
4566  wxBusyInfo wait(_T("Processing Fourier Map..."));
4567  mvpUnitCellMapGLList[choice]->GenList();
4568  }
4569  }
4570  mvpUnitCellMapGLList[choice]->SetColour(col.Red()/255.0,col.Green()/255.0,col.Blue()/255.0,0.5);
4571  }
4572  mpFourierMapListWin->mMutex.Unlock();
4573  }
4574 
4575  if(event.GetId()==ID_GLCRYSTAL_FOURIER_LISTMAP)
4576  {// Selected one map
4577  mpFourierMapListWin->mMutex.Lock();
4578  if(mpFourierMapListWin->mpAvailableMapList->GetSelection()>=0)
4579  {
4580  boost::shared_ptr<ObjCryst::UnitCellMap> pMap=mvpUnitCellMap[mpFourierMapListWin->mpAvailableMapList->GetSelection()];
4581  mpFourierMapListWin->mpMapInfo->SetLabel(wxString::Format(_T("min=%5.2f max=%5.2f sigma=%5.2f"),
4582  pMap->Min(),pMap->Max(),pMap->StandardDeviation()));
4583  }
4584  mpFourierMapListWin->mMutex.Unlock();
4585  }
4586  if(event.GetId()==ID_GLCRYSTAL_FOURIER_LISTGLMAP)
4587  {
4588  mpFourierMapListWin->mMutex.Lock();
4589  if(mpFourierMapListWin->mpDisplayedMapList->GetSelection()>=0)
4590  {
4591  boost::shared_ptr<UnitCellMapGLList> pMap=mvpUnitCellMapGLList[mpFourierMapListWin->mpDisplayedMapList->GetSelection()];
4592  mpFourierMapListWin->mpContourValue->SetValue(wxString::Format(_T("%5.2f"),pMap->GetContour()));
4593  mpFourierMapListWin->mpColourPicker->SetColour(wxColour(pMap->GetColour()[0]*255,pMap->GetColour()[1]*255,
4594  pMap->GetColour()[2]*255,pMap->GetColour()[3]*255));
4595  }
4596  mpFourierMapListWin->mMutex.Unlock();
4597  }
4598  if((event.GetId()==ID_GLCRYSTAL_FOURIER_ADD)||(event.GetId()==ID_GLCRYSTAL_FOURIER_NEWCONTOUR))
4599  {
4600  mpFourierMapListWin->mMutex.Lock();
4601  if(mpFourierMapListWin->mpAvailableMapList->GetSelection()!=wxNOT_FOUND)
4602  {
4603  boost::shared_ptr<ObjCryst::UnitCellMap> pMap=mvpUnitCellMap[mpFourierMapListWin->mpAvailableMapList->GetSelection()];
4604  double contour=0;
4605  wxString scontour=mpFourierMapListWin->mpNewContourValue->GetValue();
4606  if(scontour==_T("")) contour=pMap->Min()+pMap->StandardDeviation()*3;
4607  else scontour.ToDouble(&contour);
4608  wxColor ncolor(255,0,0);
4609  ncolor = wxGetColourFromUser((wxWindow*)this, ncolor);
4610 
4611  wxBusyInfo wait(_T("Processing Fourier Map..."));
4612  mvpUnitCellMapGLList.push_back(boost::shared_ptr<UnitCellMapGLList>(new UnitCellMapGLList(*pMap,this,true,(float)contour)));
4613  mvpUnitCellMapGLList.back()->SetName(pMap->GetName());
4614  mvpUnitCellMapGLList.back()->SetColour(ncolor.Red()/255.0,ncolor.Green()/255.0,ncolor.Blue()/255.0,0.5);
4615  mpFourierMapListWin->mMutex.Unlock();
4616  if(false==mpWXCrystal->GetCrystal().IsBeingRefined())
4617  {
4618  this->SetCurrent();
4619  mvpUnitCellMapGLList.back()->GenList();
4620  }
4621  }
4622  }
4623  if(event.GetId()==ID_GLCRYSTAL_FOURIER_REMOVE)
4624  {
4625  mpFourierMapListWin->mMutex.Lock();
4626  unsigned int choice=mpFourierMapListWin->mpDisplayedMapList->GetSelection();
4627  if(wxNOT_FOUND!=choice)
4628  mvpUnitCellMapGLList.erase(mvpUnitCellMapGLList.begin()+choice);
4629  mpFourierMapListWin->mMutex.Unlock();
4630  }
4631  if(event.GetId()==ID_GLCRYSTAL_FOURIER_SHOW)
4632  {
4633  mpFourierMapListWin->mMutex.Lock();
4634  mShowFourier=mpFourierMapListWin->mpShowFourier->GetValue();
4635  mpFourierMapListWin->mMutex.Unlock();
4636  }
4637  if(event.GetId()==ID_GLCRYSTAL_FOURIER_WIREFRAME)
4638  {
4639  mpFourierMapListWin->mMutex.Lock();
4640  vector<boost::shared_ptr<UnitCellMapGLList> >::iterator pos;
4641  for(pos=mvpUnitCellMapGLList.begin();pos != mvpUnitCellMapGLList.end();pos++)
4642  (*pos)->ToggleShowWire();
4643  mpFourierMapListWin->mMutex.Unlock();
4644  }
4645 
4646  if(event.GetId()==ID_GLCRYSTAL_FOURIER_SHARPEN)
4647  {
4648  mpFourierMapListWin->mMutex.Lock();
4649  mSharpenMap=mpFourierMapListWin->mpSharpenMap->GetValue();
4650  mpFourierMapListWin->mMutex.Unlock();
4651  }
4652 
4653  // Update - if the crystal is being refined, it will be done at the next display update
4654  if(false==mpWXCrystal->GetCrystal().IsBeingRefined())
4655  this->CrystUpdate();
4656 }
4657 
4658 void WXGLCrystalCanvas::OnLoadFourierGRD( wxCommandEvent & WXUNUSED(event))
4659 {
4660  wxFileDialog fd((wxWindow*)this, _T("Choose a file containing a Fourier Map"),
4661  _T(""), _T(""), _T("Fourier Map files (*.grd)|*.grd"), wxFD_OPEN | wxFD_FILE_MUST_EXIST);
4662  //if okay then read Fourier map, run MC on it and display the triangles
4663  if(fd.ShowModal() == wxID_OK)
4664  {
4665  const string filename(fd.GetPath().ToAscii());
4666  UnitCellMap *pMap=new UnitCellMap(mpWXCrystal->GetCrystal());
4667  if (pMap->ImportGRD(filename) == 0)
4668  {
4669  string tmp="Error reading Fourier file:"+filename;
4670  wxMessageBox( wxString::FromAscii(tmp.c_str()), _T("File error"), wxOK, this);
4671  return;
4672  }
4673  this->AddFourier(pMap);
4674  }
4675 }
4676 
4677 void WXGLCrystalCanvas::OnLoadFourierDSN6( wxCommandEvent & WXUNUSED(event))
4678 {
4679  wxFileDialog fd((wxWindow*)this, _T("Choose a file containing a Fourier Map"),
4680  _T(""), _T(""), _T("Fourier Map files (*.DN6)|*.DN6"), wxFD_OPEN | wxFD_FILE_MUST_EXIST);
4681  //if okay then read Fourier map, run MC on it and display the triangles
4682  if(fd.ShowModal() == wxID_OK)
4683  {
4684  const string filename(fd.GetPath().ToAscii());
4685  UnitCellMap *pMap=new UnitCellMap(mpWXCrystal->GetCrystal());
4686  if (pMap->ImportDSN6(filename) == 0)
4687  {
4688  string tmp="Error reading Fourier file:"+filename;
4689  wxMessageBox( wxString::FromAscii(tmp.c_str()), _T("File error"), wxOK, this);
4690  return;
4691  }
4692  this->AddFourier(pMap);
4693  }
4694 }
4695 
4696 void WXGLCrystalCanvas::AddFourier(UnitCellMap *map)
4697 {
4698  mvpUnitCellMap.push_back(boost::shared_ptr<UnitCellMap>(map));
4699  wxBusyInfo wait(_T("Processing Fourier Map..."));
4700  {
4701  float contour=map->Mean()+2*map->StandardDeviation();
4702  if(contour>map->Max()) contour=map->Mean()+0.75*(map->Max()-map->Mean());
4703  mvpUnitCellMapGLList.push_back(boost::shared_ptr<UnitCellMapGLList>(new UnitCellMapGLList(*map,this)));
4704  switch(mvpUnitCellMapGLList.size())
4705  {
4706  case 1: mvpUnitCellMapGLList.back()->SetColour(1.,0.,0.,.5);break;
4707  case 2: mvpUnitCellMapGLList.back()->SetColour(0.,0.,1.,.5);break;
4708  default:mvpUnitCellMapGLList.back()->SetColour(0.,1.,0.,.5);break;
4709  }
4710  this->SetCurrent();
4711  mvpUnitCellMapGLList.back()->GenList();
4712  mvpUnitCellMapGLList.back()->SetName(map->GetName());
4713  }
4714  if(!(mpWXCrystal->GetCrystal().IsBeingRefined())) this->CrystUpdate();
4715 }
4716 
4717 
4718 void WXGLCrystalCanvas::OnFourierChangeColour(wxColourPickerEvent &event)
4719 {
4720  mpFourierMapListWin->mMutex.Lock();
4721  //Changed colour or contour ?
4722  unsigned int choice=mpFourierMapListWin->mpDisplayedMapList->GetSelection();
4723  if(wxNOT_FOUND!=choice)
4724  {
4725  double contour;
4726  mpFourierMapListWin->mpContourValue->GetValue().ToDouble(&contour);
4727  wxColour col(mpFourierMapListWin->mpColourPicker->GetColour());
4728  if(abs((float)contour-mvpUnitCellMapGLList[choice]->GetContour())>.0001)
4729  {
4730  wxBusyInfo wait(_T("Processing Fourier Map..."));
4731  mvpUnitCellMapGLList[choice]->SetContour((float)contour);
4732  mvpUnitCellMapGLList[choice]->GenList();
4733  }
4734  mvpUnitCellMapGLList[choice]->SetColour(col.Red()/255.0,col.Green()/255.0,col.Blue()/255.0,0.5);
4735  }
4736  mpFourierMapListWin->mMutex.Unlock();
4737  mpWXCrystal->GetCrystal().UpdateDisplay();
4738 }
4739 
4740 /*
4741 void WXGLCrystalCanvas::OnUnloadFourier( wxCommandEvent & WXUNUSED(event))
4742 {
4743  wxMessageDialog * msure = new wxMessageDialog((wxWindow*)this,
4744  "Are you sure you want to unload all Fourier Map Data?", "Unload Fourier Map", wxYES_NO | wxNO_DEFAULT |
4745  wxICON_QUESTION );
4746  if(msure->ShowModal() == wxID_YES)
4747  {
4748  mvpUnitCellMap.clear();
4749  mvpUnitCellMapGLList.clear();
4750  mpPopUpMenu->SetLabel(ID_GLCRYSTAL_MENU_SHOWCRYSTAL, "Hide Crystal");
4751  mpPopUpMenu->Enable(ID_GLCRYSTAL_MENU_CHANGECONTOUR, FALSE); //disable all of these
4752  mpPopUpMenu->Enable(ID_GLCRYSTAL_MENU_ADDCONTOUR, FALSE); //disable all of these
4753  mpPopUpMenu->Enable(ID_GLCRYSTAL_MENU_SHOWFOURIER, FALSE);
4754  mpPopUpMenu->SetLabel(ID_GLCRYSTAL_MENU_SHOWFOURIER, "Hide Fourier Map");
4755  mpPopUpMenu->Enable(ID_GLCRYSTAL_MENU_UNLOADFOURIER, FALSE);
4756  mpPopUpMenu->Enable(ID_GLCRYSTAL_MENU_FOURIERCHANGECOLOR, FALSE);
4757  mpPopUpMenu->SetLabel(ID_GLCRYSTAL_MENU_SHOWWIRE, "Show Filled");
4758  mpPopUpMenu->Enable(ID_GLCRYSTAL_MENU_SHOWWIRE, FALSE);
4759  mpPopUpMenu->Enable(ID_GLCRYSTAL_MENU_FOURIERCHANGEBBOX, FALSE);
4760 
4761  this->CrystUpdate();
4762  }
4763  delete msure;
4764 }
4765 */
4766 void WXGLCrystalCanvas::OnPOVRay( wxCommandEvent & WXUNUSED(event))
4767 {
4769  wxFileDialog save(this,_T("Choose filename"),_T(""),_T(""),_T("*.pov"),wxFD_SAVE | wxFD_OVERWRITE_PROMPT);
4770  if(save.ShowModal() != wxID_OK) return;
4771  this->POVRayOutput(string(save.GetPath().char_str()));
4772 }
4773 
4774 void WXGLCrystalCanvas::POVRayOutput(const std::string &filename)
4775 {
4776  ofstream os(filename.c_str());
4777 
4778  os << "#version 3.6 ;"<<endl
4779  << "// This File was created by FOX/ObjCryst++ (http://objcryst.sf.net)"<<endl
4780  << "//"<<endl
4781  << "// You can produce a ray-traced image using POV-Ray, freely available"<<endl
4782  << "//from http://www.povray.org"<<endl
4783  << "//"<<endl
4784  << "// Example command line to produce an anti-aliase 640x480 image: "<<endl
4785  << "// povray +Ifile.pov +.pov +W640 +H480 +A +Q11"<<endl
4786  << "// You can add '+UA' at the end to have a transparent background"<<endl
4787  << "// You can add '+kff10' to generate 10 rotated images for an animation"<<endl
4788  << "// (see the 'clock' in the 'OrientPitch' definition below)"<<endl
4789  << "//"<<endl
4790  << "// Notes:"<<endl
4791  << "// - This POVRay file is written to produce a 4/3 image, e.g. 640x480"<<endl
4792  << "// If your image in the FOX 3D view was not 4/3, some parts may be cut"<<endl
4793  << "// You can then get the full structure by increasing the 'angle' "<<endl
4794  << "// (viewing angle) in the camera settings below."<<endl
4795  << "// You can change the aspect ratio (e.g. to produce a square image)"<<endl
4796  << "// by changing the 'right <-1.33,0,0>' statement in the camera definition"<<endl
4797  << "// - You can change the orientation of the view by changing the"<<endl
4798  << "// OrientRoll, OrientPitch and OrientYaw angles just below (in degrees)"<<endl
4799  << "// - You can change the aspects of atoms by altering the macros below."<<endl
4800  << "// The radius of atoms is by default 1/3 of their tabulated atomic radius,"<<endl
4801  << "// i.e. as in the FOX/ObjCryst++ 3D Crystal view. To modify this you can"<<endl
4802  << "// change the second line of the 'ObjCrystAtom' macro to (e.g. for full radius):"<<endl
4803  << "// '{ <atomx,atomy,atomz>,atomr*1.0'"<<endl
4804  << "// - The colour of atoms, bonds (free and non-free torsions) can be changed"<<endl
4805  << "// in the 'GLOBAL DECLARATIONS FOR ATOMS & BONDS' section"<<endl
4806  << "// - Just for fun, you can try getting *very close* to one of the atoms,"<<endl
4807  << "// and, in the 'ObjCrystAtom' macro at the end of the 'finish'"<<endl
4808  << "// statement, change the 'reflection' value to 1.0, "<<endl
4809  << "// to get a mirror effect on the atoms..."<<endl
4810  << "//"<<endl
4811  << "// See http://povray.org/documentation/ for more options"<<endl
4812  << "//"<<endl<<endl;
4813 
4814  os << "// Description of Crystal :" << mpWXCrystal->GetCrystal().GetName() <<endl;
4815  os << "global_settings { assumed_gamma 2.2 ambient_light rgb <1,1,1>}"<<endl;
4816  float m[4][4];
4817  REAL xcam=0,ycam=0,zcam=mDist;
4818  build_rotmatrix( m,mQuat);
4819 
4820  REAL x=(mcellbbox.xMin+mcellbbox.xMax)/2.;
4821  REAL y=(mcellbbox.yMin+mcellbbox.yMax)/2.;
4822  REAL z=(mcellbbox.zMin+mcellbbox.zMax)/2.;
4823  mpWXCrystal->GetCrystal().FractionalToOrthonormalCoords(x,y,z);
4824  x-=mX0;
4825  y-=mY0;
4826  z-=mZ0;
4827  {
4828  const REAL q1=mQuat[0];const REAL q2=mQuat[1];
4829  const REAL q3=mQuat[2];const REAL q4=mQuat[3];
4830 
4831  REAL yaw =(q4*q4 + q1*q1 - q2*q2 - q3*q3);
4832  if(abs(yaw)>1e-6) yaw =atan( 2*(q1*q2+q4*q3) /yaw )*RAD2DEG;
4833  else { if((q1*q2+q4*q3)>0) yaw =90.; else yaw =-90;}
4834 
4835  const REAL pitch=asin(-2*(q1*q3-q4*q2))*RAD2DEG;
4836 
4837  REAL roll=(q4*q4 - q1*q1 - q2*q2 + q3*q3);
4838  if(abs(roll)>1e-6) roll =atan( 2*(q4*q1+q2*q3) /roll)*RAD2DEG;
4839  else { if((q4*q1+q2*q3)>0) roll=90.; else roll=-90;}
4840 
4841  if((q4*q4 + q1*q1 - q2*q2 - q3*q3)<0) yaw +=180;
4842  if((q4*q4 - q1*q1 - q2*q2 + q3*q3)<0) roll +=180;
4843 
4844  os<<endl;
4845  os << "#declare OrientRoll="<<roll<<";"<<endl;
4846  os << "#declare OrientPitch="<<pitch<<"+360*clock;"<<endl;
4847  os << "#declare OrientYaw="<<yaw<<";"<<endl<<endl;
4848  }
4849 
4850  os << "camera" <<endl;
4851  os << "{"<<endl;
4852  os << " location <"<<xcam+x<<","<<ycam+y<<","<<zcam+z<<">"<<endl
4853  << " look_at <" << x << "," << y << "," << z <<">"<<endl
4854  << " angle "<< mViewAngle*1.2 <<endl
4855  << " right <-1.33,0,0> //change handedness as in OpenGL, aspect ratio=4/3"<<endl
4856  << " translate <" <<-x << "," <<-y << "," <<-z <<">"<<endl
4857  << " rotate <OrientRoll,0,0>" <<endl
4858  << " rotate <0,OrientPitch,0>" <<endl
4859  << " rotate <0,0,OrientYaw>" <<endl
4860  << " translate <" << x << "," << y << "," << z <<">"<<endl
4861  << "}"<<endl;
4862 
4863  REAL xlight=-1000,ylight=1000,zlight=1000;
4864  os << "light_source"<<endl;
4865  os << "{" <<endl
4866  << " <"<<xlight<<","<<ylight<<","<<zlight<<">"<<endl
4867  << " colour rgb <1.0,1.0,1.0>" <<endl
4868  << " //shadowless" <<endl
4869  << " translate <" <<-x << "," <<-y << "," <<-z <<">"<<endl
4870  << " rotate <OrientRoll,0,0>" <<endl
4871  << " rotate <0,OrientPitch,0>" <<endl
4872  << " rotate <0,0,OrientYaw>" <<endl
4873  << " translate <" << x << "," << y << "," << z <<">"<<endl
4874  << "}" <<endl<<endl;
4875 
4876  os << "background { colour rgb <0.0, 0.0, 0.0> }"<<endl<<endl;
4877 
4878  CrystalPOVRayOptions options;
4879  options.mXmin=mcellbbox.xMin;
4880  options.mXmax=mcellbbox.xMax;
4881  options.mYmin=mcellbbox.yMin;
4882  options.mYmax=mcellbbox.yMax;
4883  options.mZmin=mcellbbox.zMin;
4884  options.mZmax=mcellbbox.zMax;
4885  options.mShowLabel=mShowAtomName;
4886  options.mShowHydrogens=mShowHydrogens;
4887  if(mShowCrystal)
4888  {
4889  mpWXCrystal->GetCrystal().POVRayDescription(os,options);
4890  }
4891  if(mShowFourier)
4892  {
4893  wxBusyInfo wait(_T("Processing Fourier Map..."));
4894  // use cell bbox if mapbbox has zero volume (default)
4895  if (mmapbbox.xMin != mmapbbox.xMax)
4896  {
4897  options.mXmin=mmapbbox.xMin;
4898  options.mXmax=mmapbbox.xMax;
4899  options.mYmin=mmapbbox.yMin;
4900  options.mYmax=mmapbbox.yMax;
4901  options.mZmin=mmapbbox.zMin;
4902  options.mZmax=mmapbbox.zMax;
4903  }
4904 
4905  os<<"/////////////////// FOURIER MAPS///////////////////////////"<<endl;
4906  vector<boost::shared_ptr<UnitCellMapGLList> >::const_iterator pos;
4907  for(pos=mvpUnitCellMapGLList.begin();pos != mvpUnitCellMapGLList.end();++pos)
4908  {
4909  const float *prgbf=(*pos)->GetColour();
4910  if((*pos)->ShowWire())
4911  {
4912  os << "#macro ObjCrystMeshTriangle(x1,y1,z1,x2,y2,z2,x3,y3,z3,"
4913  << "nx1,ny1,nz1,nx2,ny2,nz2,nx3,ny3,nz3)"<<endl
4914  << " cylinder"<<endl
4915  << " { <x1,y1,z1>,"<<endl
4916  << " <x2,y2,z2>,"<<endl
4917  << " 0.01"<<endl
4918  << " finish {ambient 0.5 diffuse 0.4}"<<endl
4919  << " pigment { colour rgb<"
4920  <<*(prgbf+0)<<","<<*(prgbf+1)<<","<<*(prgbf+2)<<">}"<<endl
4921  << " no_shadow"<<endl
4922  << " }"<<endl
4923  << " cylinder"<<endl
4924  << " { <x2,y2,z2>,"<<endl
4925  << " <x3,y3,z3>,"<<endl
4926  << " 0.01"<<endl
4927  << " finish {ambient 0.5 diffuse 0.4}"<<endl
4928  << " pigment { colour rgb<"
4929  <<*(prgbf+0)<<","<<*(prgbf+1)<<","<<*(prgbf+2)<<">}"<<endl
4930  << " no_shadow"<<endl
4931  << " }"<<endl
4932  << " cylinder"<<endl
4933  << " { <x1,y1,z1>,"<<endl
4934  << " <x3,y3,z3>,"<<endl
4935  << " 0.01"<<endl
4936  << " finish {ambient 0.5 diffuse 0.4}"<<endl
4937  << " pigment { colour rgb<"
4938  <<*(prgbf+0)<<","<<*(prgbf+1)<<","<<*(prgbf+2)<<">}"<<endl
4939  << " no_shadow"<<endl
4940  << " }"<<endl
4941  << "#end"<<endl<<endl;
4942  (*pos)->GetMap().POVRayDescription(os,(*pos)->GetContour(),options);
4943  }
4944  else
4945  {
4946  os << "#macro ObjCrystMeshTriangle(x1,y1,z1,x2,y2,z2,x3,y3,z3,"
4947  << "nx1,ny1,nz1,nx2,ny2,nz2,nx3,ny3,nz3)"<<endl
4948  << " smooth_triangle"<<endl
4949  <<" {<x1,y1,z1>,<nx1,ny1,nz1>"<<endl
4950  <<" <x2,y2,z2>,<nx2,ny2,nz2>"<<endl
4951  <<" <x3,y3,z3>,<nx3,ny3,nz3>}"<<endl
4952  << "#end"<<endl<<endl;
4953  os << " mesh"<<endl
4954  << " {"<<endl;
4955  (*pos)->GetMap().POVRayDescription(os,(*pos)->GetContour(),options);
4956  os << " texture"<<endl
4957  << " {"<<endl
4958  << " finish {ambient 0.5 diffuse 0.4}"<<endl
4959  << " pigment { colour rgb<"
4960  <<*prgbf++<<",";
4961  os <<*prgbf++<<",";
4962  os <<*prgbf++<<">}"<<endl
4963  << " }"<<endl
4964  << " no_shadow"<<endl
4965  << " }"<<endl;
4966  }
4967  }
4968 
4969  }
4970  os.close();
4971 }
4972 
4973 
4974 BBox WXGLCrystalCanvas::GetCellBBox() {
4975  return mcellbbox;
4976 }
4977 
4978 BBox WXGLCrystalCanvas::GetMapBBox() {
4979  return mmapbbox;
4980 }
4981 
4982 REAL WXGLCrystalCanvas::GetFadeDistance()
4983 {
4984  return mFadeDistance;
4985 }
4986 
4987 void WXGLCrystalCanvas::UnProject(REAL &x, REAL &y, REAL &z)
4988 {
4989  GLdouble vx,vy,vz,junk;
4990  GLdouble z0;
4991  GLdouble modelMatrix[16];
4992  GLdouble projMatrix[16];
4993  GLint viewport[4];
4994 
4995  this->SetCurrent();
4996  glMatrixMode( GL_MODELVIEW );
4997  glLoadIdentity();
4998  glTranslatef( 0, 0, -mDist );
4999 
5000  glGetDoublev(GL_MODELVIEW_MATRIX,modelMatrix);
5001  glGetDoublev(GL_PROJECTION_MATRIX,projMatrix);
5002  glGetIntegerv(GL_VIEWPORT,viewport);
5003 
5004  // First, get the z depth of where we want to translate
5005  gluProject(0, 0, 0 ,modelMatrix,projMatrix,viewport,&junk,&junk,&z0);
5006  // Get the orthonormal coordinates
5007  gluUnProject(x,y,z0,modelMatrix,projMatrix,viewport,&vx,&vy,&vz);
5008  vy = -vy;
5009  // Use Quaternion to get the correct position
5010  GLfloat m[4][4];
5011  build_rotmatrix( m,mQuat);
5012 
5013  x= m[0][0]* vx + m[0][1]*vy + m[0][2]*vz -mX0;
5014  y= m[1][0]* vx + m[1][1]*vy + m[1][2]*vz -mY0;
5015  z= m[2][0]* vx + m[2][1]*vy + m[2][2]*vz -mZ0;
5016  VFN_DEBUG_MESSAGE("WXGLCrystalCanvas::UnProject():X Y Z = "<<x<<" , "<<y<<" , "<<z,5)
5017 }
5018 #ifndef HAVE_GLUT
5019 void WXGLCrystalCanvas::BuildGLFont()
5020 {
5021  if(mIsGLFontBuilt) return;
5022  VFN_DEBUG_ENTRY("WXGLCrystalCanvas::BuildGLFont()-gldisplay",6)
5023  #ifdef __LINUX__
5024  Display *dpy;
5025  XFontStruct *fontInfo=NULL;
5026 
5027  mGLFontDisplayListBase = glGenLists(96);
5028 
5029  dpy = XOpenDisplay(NULL);
5030 
5031  fontInfo = XLoadQueryFont(dpy, "-adobe-helvetica-bold-*-r-*-10-*-*-*-*-*-*-*");
5032  if (fontInfo == NULL)
5033  fontInfo = XLoadQueryFont(dpy, "-adobe-helvetica-bold-*-*-*-10-*-*-*-*-*-*-*");
5034  if (fontInfo == NULL)
5035  fontInfo = XLoadQueryFont(dpy, "-adobe-times-bold-*-r-*-10-*-*-*-*-*-*-*");
5036  if (fontInfo == NULL)
5037  fontInfo = XLoadQueryFont(dpy, "-adobe-helvetica-medium-*-*-*-12-*-*-*-*-*-*-*");
5038  if (fontInfo == NULL)
5039  fontInfo = XLoadQueryFont(dpy, "-adobe-times-medium-*-*-*-12-*-*-*-*-*-*-*");
5040  if (fontInfo == NULL)
5041  fontInfo = XLoadQueryFont(dpy, "-adobe-helvetica-*-*-*-*-12-*-*-*-*-*-*-*");
5042  if (fontInfo == NULL)
5043  fontInfo = XLoadQueryFont(dpy, "-adobe-times-*-*-*-*-12-*-*-*-*-*-*-*");
5044  if (fontInfo == NULL)
5045  fontInfo = XLoadQueryFont(dpy, "fixed");
5046  if (fontInfo == NULL) cout <<"no X font available..."<<endl;
5047 
5048  glXUseXFont(fontInfo->fid, 32, 96, mGLFontDisplayListBase);
5049  XFreeFont(dpy, fontInfo);
5050  XCloseDisplay(dpy);
5051  #endif
5052  #ifdef __WIN32__
5053  HFONT font;
5054  HFONT oldfont;
5055  wxPaintDC dc(this);
5056  HDC hDC = (HDC)dc.GetHDC();
5057  // Use 3mm font size
5058  wxSize s = dc.GetPPI();
5059  int height = int(round(3 * (s.GetHeight() + s.GetWidth()) / 2 / 25.4));
5060  mGLFontDisplayListBase = 100;
5061  font = CreateFont(-height, // Height of font
5062  0, // Width of font
5063  0, // Angle of escapement
5064  0, // Orientation angle
5065  FW_NORMAL, // Font weight
5066  FALSE, // Italic
5067  FALSE, // Underline
5068  FALSE, // Strikeout
5069  ANSI_CHARSET, // Character set identifier
5070  OUT_TT_PRECIS, // Output precision
5071  CLIP_DEFAULT_PRECIS, // Clipping precision
5072  ANTIALIASED_QUALITY, // Output quality
5073  FF_DONTCARE|DEFAULT_PITCH, // Family and pitch
5074  _T("Helvetica")); // Font name
5075 
5076  oldfont = (HFONT)SelectObject(hDC, font);
5077  wglUseFontBitmaps(hDC, 0, 128, mGLFontDisplayListBase);
5078  SelectObject(hDC, oldfont);
5079  DeleteObject(font);
5080  #endif
5081  mIsGLFontBuilt=true;
5082  sFontDisplayListBase=mGLFontDisplayListBase;
5083  VFN_DEBUG_EXIT("WXGLCrystalCanvas::BuildGLFont()",6)
5084 }
5085 
5086 void WXGLCrystalCanvas::DeleteGLFont() const
5087 {
5088  if(!mIsGLFontBuilt) return;
5089  glDeleteLists(mGLFontDisplayListBase, 96);
5090  mIsGLFontBuilt=false;
5091  mGLFontDisplayListBase=0;
5092 }
5093 #endif
5094 
5095 
5097 //
5098 // UserSelectBoundingBox
5099 //
5101 BEGIN_EVENT_TABLE(UserSelectBoundingBox, wxDialog)
5102  EVT_BUTTON(wxID_OK, UserSelectBoundingBox::OnOk)
5103 END_EVENT_TABLE()
5104 
5105  UserSelectBoundingBox::UserSelectBoundingBox (wxWindow *parent, const char * title,
5106  const BBox bbox)
5107  : wxDialog((wxWindow *)parent, -1, _T("Set bounding box"), wxDefaultPosition,
5108  wxSize(250, 250), wxDEFAULT_DIALOG_STYLE)
5109 {
5110  wxBoxSizer *dialogSizer = new wxBoxSizer(wxVERTICAL);
5111  wxFlexGridSizer *inputSizer = new wxFlexGridSizer(4, 3, 10, 10);
5112  // headers
5113  inputSizer->Add(new wxStaticText(this, -1, _T("")), 0, wxALIGN_CENTRE_VERTICAL);
5114  inputSizer->Add(new wxStaticText(this, -1, _T("minimum")), 0, wxALIGN_CENTER);
5115  inputSizer->Add(new wxStaticText(this, -1, _T("maximum")), 0, wxALIGN_CENTER);
5116  // 1st row
5117  inputSizer->Add(new wxStaticText(this, -1, _T("a")), 0, wxALIGN_CENTRE_VERTICAL);
5118  inputSizer->Add(mpXminCtrl = new wxTextCtrl(this, -1,
5119  wxString::Format(_T("%f"),bbox.xMin), wxDefaultPosition,
5120  wxDefaultSize, 0, wxTextValidator(wxFILTER_NUMERIC)),
5121  0, wxALIGN_CENTRE_VERTICAL);
5122  inputSizer->Add(mpXmaxCtrl = new wxTextCtrl(this, -1,
5123  wxString::Format(_T("%f"),bbox.xMax), wxDefaultPosition,
5124  wxDefaultSize, 0, wxTextValidator(wxFILTER_NUMERIC)),
5125  0, wxALIGN_CENTRE_VERTICAL);
5126  // 2nd row
5127  inputSizer->Add(new wxStaticText(this, -1, _T("b")), 0, wxALIGN_CENTRE_VERTICAL);
5128  inputSizer->Add(mpYminCtrl = new wxTextCtrl(this, -1,
5129  wxString::Format(_T("%f"),bbox.yMin), wxDefaultPosition,
5130  wxDefaultSize, 0, wxTextValidator(wxFILTER_NUMERIC)),
5131  0, wxALIGN_CENTRE_VERTICAL);
5132  inputSizer->Add(mpYmaxCtrl = new wxTextCtrl(this, -1,
5133  wxString::Format(_T("%f"),bbox.yMax), wxDefaultPosition,
5134  wxDefaultSize, 0, wxTextValidator(wxFILTER_NUMERIC)),
5135  0, wxALIGN_CENTRE_VERTICAL);
5136  // 3rd row
5137  inputSizer->Add(new wxStaticText(this, -1, _T("c")), 0, wxALIGN_CENTRE_VERTICAL);
5138  inputSizer->Add(mpZminCtrl = new wxTextCtrl(this, -1,
5139  wxString::Format(_T("%f"),bbox.zMin), wxDefaultPosition,
5140  wxDefaultSize, 0, wxTextValidator(wxFILTER_NUMERIC)),
5141  0, wxALIGN_CENTRE_VERTICAL);
5142  inputSizer->Add(mpZmaxCtrl = new wxTextCtrl(this, -1,
5143  wxString::Format(_T("%f"),bbox.zMax), wxDefaultPosition,
5144  wxDefaultSize, 0, wxTextValidator(wxFILTER_NUMERIC)),
5145  0, wxALIGN_CENTRE_VERTICAL);
5146  // button section
5147  wxFlexGridSizer *buttonSizer = new wxFlexGridSizer(1, 2, 10, 10);
5148  buttonSizer->Add(new wxButton(this, wxID_OK, _T("OK")),
5149  0, wxALIGN_CENTRE_VERTICAL);
5150  buttonSizer->Add(new wxButton(this, wxID_CANCEL, _T("Cancel")),
5151  0, wxALIGN_CENTRE_VERTICAL);
5152 
5153  dialogSizer->Add(10, 10);
5154  dialogSizer->Add(new wxStaticText(this, -1, wxString::FromAscii(title)), 0,
5155  wxALIGN_CENTER);
5156  dialogSizer->Add(10, 10);
5157  dialogSizer->Add(inputSizer, 0, wxALIGN_CENTER);
5158  dialogSizer->Add(20, 20);
5159  dialogSizer->Add(buttonSizer, 0, wxALIGN_CENTER);
5160 
5161  SetSizer(dialogSizer);
5162  SetAutoLayout(TRUE);
5163  Layout();
5164 }
5165 
5166 UserSelectBoundingBox::~UserSelectBoundingBox () {
5167  // if the sizers must be deleted, put them in the class and delete them here
5168  //delete dialogSizer;
5169  //delete inputSizer;
5170  //delete buttonSizer;
5171 };
5172 
5173 void UserSelectBoundingBox::OnOk (wxCommandEvent & WXUNUSED(event)) {
5174  double val;
5175 
5176  mpXminCtrl->GetValue().ToDouble(&val);
5177  mbbox.xMin = val;
5178  mpXmaxCtrl->GetValue().ToDouble(&val);
5179  mbbox.xMax = val;
5180  if (mbbox.xMin == mbbox.xMax) {wxMessageBox(_T("Sorry, Xmin must be less than Xmax!"), _T("Zero bounding volume"), wxOK, this); return;}
5181  if (mbbox.xMin > mbbox.xMax) {
5182  float tmp = mbbox.xMax;
5183  mbbox.xMax = mbbox.xMin;
5184  mbbox.xMin = tmp;
5185  }
5186  VFN_DEBUG_MESSAGE("Xmin " << mbbox.xMin << " Xmax " << mbbox.xMax,1)
5187 
5188  mpYminCtrl->GetValue().ToDouble(&val);
5189  mbbox.yMin = val;
5190  mpYmaxCtrl->GetValue().ToDouble(&val);
5191  mbbox.yMax = val;
5192  if (mbbox.yMin == mbbox.yMax) {wxMessageBox(_T("Sorry, Ymin must be less than Ymax!"), _T("Zero bounding volume"), wxOK, this); return;}
5193  if (mbbox.yMin > mbbox.yMax) {
5194  float tmp = mbbox.yMax;
5195  mbbox.yMax = mbbox.yMin;
5196  mbbox.yMin = tmp;
5197  }
5198  VFN_DEBUG_MESSAGE("Ymin " << mbbox.yMin << " Ymax " << mbbox.yMax,1)
5199 
5200  mpZminCtrl->GetValue().ToDouble(&val);
5201  mbbox.zMin = val;
5202  mpZmaxCtrl->GetValue().ToDouble(&val);
5203  mbbox.zMax = val;
5204  if (mbbox.zMin == mbbox.zMax) {wxMessageBox(_T("Sorry, Zmin must be less than Zmax!"), _T("Zero bounding volume"), wxOK, this); return;}
5205  if (mbbox.zMin > mbbox.zMax) {
5206  float tmp = mbbox.zMax;
5207  mbbox.zMax = mbbox.zMin;
5208  mbbox.zMin = tmp;
5209  }
5210  VFN_DEBUG_MESSAGE("Zmin " << mbbox.zMin << " Zmax " << mbbox.zMax,1)
5211 
5212  // close the dialog
5213  EndModal(wxID_OK);
5214 }
5215 
5216 BBox UserSelectBoundingBox::GetBBox () {
5217  return mbbox;
5218 }
5219 
5220 
5222 //
5223 // UserXYZBox
5224 //
5226 BEGIN_EVENT_TABLE(UserXYZBox, wxDialog)
5227  EVT_BUTTON(wxID_OK, UserXYZBox::OnOk)
5228 END_EVENT_TABLE()
5229 
5230  UserXYZBox::UserXYZBox (wxWindow *parent, const wxString &title,
5231  const Triple xyz)
5232  : wxDialog((wxWindow *)parent, -1, _T("Set position"), wxDefaultPosition,
5233  wxSize(250, 250), wxDEFAULT_DIALOG_STYLE)
5234 {
5235  wxBoxSizer *dialogSizer = new wxBoxSizer(wxVERTICAL);
5236  wxFlexGridSizer *inputSizer = new wxFlexGridSizer(3, 2, 10, 10);
5237  // 1st row
5238  inputSizer->Add(new wxStaticText(this, -1, _T("x")), 0, wxALIGN_CENTRE_VERTICAL);
5239  inputSizer->Add(mpXCtrl = new wxTextCtrl(this, -1,
5240  wxString::Format(_T("%.3f"),xyz.x), wxDefaultPosition, wxDefaultSize,
5241  wxTE_CENTRE, wxTextValidator(wxFILTER_NUMERIC)),
5242  0, wxALIGN_CENTRE_VERTICAL);
5243  // 2nd row
5244  inputSizer->Add(new wxStaticText(this, -1, _T("y")), 0, wxALIGN_CENTRE_VERTICAL);
5245  inputSizer->Add(mpYCtrl = new wxTextCtrl(this, -1,
5246  wxString::Format(_T("%.3f"),xyz.y), wxDefaultPosition, wxDefaultSize,
5247  wxTE_CENTRE, wxTextValidator(wxFILTER_NUMERIC)),
5248  0, wxALIGN_CENTRE_VERTICAL);
5249  // 3rd row
5250  inputSizer->Add(new wxStaticText(this, -1, _T("z")), 0, wxALIGN_CENTRE_VERTICAL);
5251  inputSizer->Add(mpZCtrl = new wxTextCtrl(this, -1,
5252  wxString::Format(_T("%.3f"),xyz.z), wxDefaultPosition, wxDefaultSize,
5253  wxTE_CENTRE, wxTextValidator(wxFILTER_NUMERIC)),
5254  0, wxALIGN_CENTRE_VERTICAL);
5255  // button section
5256  wxFlexGridSizer *buttonSizer = new wxFlexGridSizer(1, 2, 10, 10);
5257  buttonSizer->Add(new wxButton(this, wxID_OK, _T("OK")),
5258  0, wxALIGN_CENTRE_VERTICAL);
5259  buttonSizer->Add(new wxButton(this, wxID_CANCEL, _T("Cancel")),
5260  0, wxALIGN_CENTRE_VERTICAL);
5261 
5262  dialogSizer->Add(10, 10);
5263  dialogSizer->Add(new wxStaticText(this, -1, title), 0,
5264  wxALIGN_CENTER);
5265  dialogSizer->Add(10, 10);
5266  dialogSizer->Add(inputSizer, 0, wxALIGN_CENTER);
5267  dialogSizer->Add(20, 20);
5268  dialogSizer->Add(buttonSizer, 0, wxALIGN_CENTER);
5269 
5270  SetSizer(dialogSizer);
5271  SetAutoLayout(TRUE);
5272  Layout();
5273 }
5274 
5275 UserXYZBox::~UserXYZBox () {
5276 };
5277 
5278 void UserXYZBox::OnOk (wxCommandEvent & WXUNUSED(event))
5279 {
5280  double tmp;
5281  mpXCtrl->GetValue().ToDouble(&tmp);
5282  mXYZ.x = tmp;
5283 
5284  mpYCtrl->GetValue().ToDouble(&tmp);
5285  mXYZ.y = tmp;
5286 
5287  mpZCtrl->GetValue().ToDouble(&tmp);
5288  mXYZ.z = tmp;
5289 
5290  // close the dialog
5291  EndModal(wxID_OK);
5292 }
5293 
5294 Triple UserXYZBox::GetXYZ () {
5295  return mXYZ;
5296 }
5297 
5298 
5299 #endif // #ifdef OBJCRYST_GL
5300 
5301 }// namespace
The namespace which includes all objects (crystallographic and algorithmic) in ObjCryst++.
Definition: doc-main.h:25
void WXCrystValidateAllUserInput()
This function validates all user input (in a WXField) not yet taken into account, if needs be.
Definition: wxCryst.cpp:258
Molecule * ZScatterer2Molecule(ZScatterer *scatt)
Converter from ZScatterer to a Molecule object.
Definition: Molecule.cpp:7949
std::map< wxWindowID, std::pair< wxPoint, wxSize > > gvWindowPosition
Used to remember window positions.
Definition: wxCryst.cpp:52
REAL GetBondAngle(const MolAtom &at1, const MolAtom &at2, const MolAtom &at3)
Get The Bond Angle of 3 atoms.
Definition: Molecule.cpp:98
T * WXDialogChooseFromRegistry(ObjRegistry< T > &reg, wxWindow *parent, const string &message, int &choice)
This function allows to pick up one object in a registry.
Crystal class: Unit cell, spacegroup, scatterers.
Definition: Crystal.h:98
std::map< pair< const ScatteringPower *, const ScatteringPower * >, Crystal::BumpMergePar > VBumpMergePar
Anti-bump parameters.
Definition: Crystal.h:337
Abstract Base Class to describe the scattering power of any Scatterer component in a crystal.
virtual const string & GetClassName() const
Name for this class ("RefinableObj", "Crystal",...).
The Scattering Power for an Atom.
virtual const string & GetName() const
Name of the object.
Simple chronometer class, with microsecond precision.
Definition: Chronometer.h:35
Definition: MC.h:22
wxCryst class for Crystals
Definition: wxCrystal.h:81
Structure to store the scattering power parameters.
Definition: wxCrystal.h:143