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