1 /* Copyright (c) 2015 Gerald Knizia
2 *
3 * This file is part of the IboView program (see: http://www.iboview.org)
4 *
5 * IboView 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, version 3.
8 *
9 * IboView is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with bfint (LICENSE). If not, see http://www.gnu.org/licenses/
16 *
17 * Please see IboView documentation in README.txt for:
18 * -- A list of included external software and their licenses. The included
19 * external software's copyright is not touched by this agreement.
20 * -- Notes on re-distribution and contributions to/further development of
21 * the IboView software
22 */
23
24 #include <QAbstractProxyModel>
25 #include <algorithm>
26 #include <math.h>
27 #include "CxVec3.h"
28 #include "Iv.h"
29 #include "IvDocument.h"
30 #include "IvTables.h"
31 #include "CtConstants.h"
32 #include "ui_TablesForm.h"
33 using std::sqrt;
34
35 // // c/p'd from http://www.qtcentre.org/wiki/index.php?title=Transpose_proxy_model
36 // class FTransposeProxyModel : public QAbstractProxyModel
37 // {
38 // public:
39 // FTransposeProxyModel(QObject *p = 0) : QAbstractProxyModel(p){}
40 //
41 // QModelIndex mapFromSource( const QModelIndex & sourceIndex ) const{
42 // return index(sourceIndex.column(), sourceIndex.row());
43 // }
44 // QModelIndex mapToSource( const QModelIndex & proxyIndex ) const{
45 // return sourceModel()->index(proxyIndex.column(), proxyIndex.row());
46 // }
47 // QModelIndex index(int r, int c, const QModelIndex &index=QModelIndex()) const{
48 // return createIndex(r,c);
49 // IR_SUPPRESS_UNUSED_WARNING(index);
50 // }
51 // QModelIndex parent(const QModelIndex&) const {
52 // return QModelIndex();
53 // }
54 // int rowCount(const QModelIndex &) const{
55 // return sourceModel()->columnCount();
56 // }
57 // int columnCount(const QModelIndex &) const{
58 // return sourceModel()->rowCount();
59 // }
60 // QVariant data(const QModelIndex &ind, int role) const {
61 // return sourceModel()->data(mapToSource(ind), role);
62 // }
63 // };
64
65 // ^- hmmm.. this doesn't work. headerData arguments are wrong (section always supplied as 0),
66 // and orientation is not patched up. maybe I just switch everything manually...
67
68
69
70
71
72
73
74
75
FMeasure(FDocument * pDocument_,QString const & UnitName_,int nDigits_,double fAuToOutFactor_)76 FMeasure::FMeasure(FDocument *pDocument_, QString const &UnitName_, int nDigits_, double fAuToOutFactor_)
77 : m_pDocument(pDocument_), m_UnitName(UnitName_), m_nDigits(nDigits_), m_AuToOut(fAuToOutFactor_)
78 {
79 }
80
~FMeasure()81 FMeasure::~FMeasure()
82 {
83 }
84
UnitName() const85 QString FMeasure::UnitName() const
86 {
87 return m_UnitName;
88 }
89
FmtValue(double f,uint Flags) const90 QString FMeasure::FmtValue(double f, uint Flags) const
91 {
92 if (0 != (Flags & FORMAT_ValueOnly))
93 return QString("%2").arg(f,0,'f',m_nDigits);
94 else
95 return QString("%1 = %2 %3").arg(Name()).arg(f,0,'f',m_nDigits).arg(UnitName());
96 }
97
MeasureFrame(FFrame * pFrame,uint Flags) const98 QString FMeasure::MeasureFrame(FFrame *pFrame, uint Flags) const
99 {
100 FFrameMeasurePtrList
101 DummyList;
102 // DummyList.push_back(FFramePtr(pFrame));
103 DummyList.push_back(pFrame);
104 FMeasureSet
105 Value;
106 MakeValues(Value, DummyList);
107 if (Value.size() != 1) {
108 IvNotify(NOTIFY_Error, IvFmt("Something went wrong while computing measure %1.", this->Name()));
109 return "!MEASURE-ERROR";
110 }
111 return FmtValue(Value[0], Flags);
112 }
113
114
115
FMeasureBondLength(int iAt_,int jAt_,FDocument * pDocument_)116 FMeasureBondLength::FMeasureBondLength(int iAt_, int jAt_, FDocument *pDocument_)
117 : FMeasure(pDocument_,"pm",2,ct::ToAng*100.), m_iAt(iAt_), m_jAt(jAt_)
118 {}
119
Name() const120 QString FMeasureBondLength::Name() const
121 {
122 return QString("r(%1--%2)").arg(m_pDocument->AtomLabel(m_iAt), m_pDocument->AtomLabel(m_jAt));
123 }
124
MakeValues(FMeasureSet & FrameValues,FFrameMeasurePtrList & Frames) const125 void FMeasureBondLength::MakeValues(FMeasureSet &FrameValues, FFrameMeasurePtrList &Frames) const
126 {
127 FrameValues.clear();
128 FrameValues.reserve(Frames.size());
129 // foreach(FFrameMeasurePtrList::value_type const *itFrame, Frames) {
130 FFrameMeasurePtrList::const_iterator itFrame;
131 _for_each(itFrame, Frames) {
132 ct::FAtomSet *pAtoms = (*itFrame)->pGetAtoms();
133 if (pAtoms && size_t(m_iAt) < pAtoms->size() && size_t(m_jAt) < pAtoms->size()) {
134 ct::FVector3
135 vI = (*pAtoms)[size_t(m_iAt)].vPos,
136 vJ = (*pAtoms)[size_t(m_jAt)].vPos;
137 FrameValues.push_back(m_AuToOut * Dist(vI, vJ));
138 } else {
139 FrameValues.push_back(0);
140 }
141 }
142 }
143
144 // return angle between Left--Center and Center--Right (in radians)
Angle(ct::FVector3 const & Left,ct::FVector3 const & Center,ct::FVector3 const & Right)145 static double Angle(ct::FVector3 const &Left, ct::FVector3 const &Center, ct::FVector3 const &Right)
146 {
147 ct::FVector3
148 vA = Normalized(Left - Center),
149 vB = Normalized(Right - Center);
150 return std::acos(Dot(vA, vB));
151 }
152
153
FMeasureBondAngle(int iAt_,int jAt_,int kAt_,FDocument * pDocument_)154 FMeasureBondAngle::FMeasureBondAngle(int iAt_, int jAt_, int kAt_, FDocument *pDocument_)
155 : FMeasure(pDocument_,QString::fromWCharArray(L"\u00b0"),2,180./M_PI), m_iAt(iAt_), m_jAt(jAt_), m_kAt(kAt_)
156 {}
157
Name() const158 QString FMeasureBondAngle::Name() const
159 {
160 return QString(QString::fromWCharArray(L"\u03b1(%1 | %2 | %3)")).arg(m_pDocument->AtomLabel(m_iAt), m_pDocument->AtomLabel(m_jAt), m_pDocument->AtomLabel(m_kAt));
161 }
162
MakeValues(FMeasureSet & FrameValues,FFrameMeasurePtrList & Frames) const163 void FMeasureBondAngle::MakeValues(FMeasureSet &FrameValues, FFrameMeasurePtrList &Frames) const
164 {
165 FrameValues.clear();
166 FrameValues.reserve(Frames.size());
167 // foreach(FFrameMeasurePtrList::value_type const *itFrame, Frames) {
168 FFrameMeasurePtrList::const_iterator itFrame;
169 _for_each(itFrame, Frames) {
170 ct::FAtomSet *pAtoms = (*itFrame)->pGetAtoms();
171 if (pAtoms && size_t(m_iAt) < pAtoms->size() && size_t(m_jAt) < pAtoms->size()) {
172 ct::FVector3
173 vI = (*pAtoms)[size_t(m_iAt)].vPos,
174 vJ = (*pAtoms)[size_t(m_jAt)].vPos,
175 vK = (*pAtoms)[size_t(m_kAt)].vPos;
176 FrameValues.push_back(m_AuToOut * Angle(vI, vJ, vK));
177 } else {
178 FrameValues.push_back(0);
179 }
180 }
181 }
182
183
184 // return angle between Left--Center and Center--Right (in radians)
Dihedral(ct::FVector3 const & vA,ct::FVector3 const & vB,ct::FVector3 const & vC,ct::FVector3 const & vD)185 static double Dihedral(ct::FVector3 const &vA, ct::FVector3 const &vB, ct::FVector3 const &vC, ct::FVector3 const &vD)
186 {
187 ct::FVector3
188 v0 = vB - vA,
189 v1 = vC - vB,
190 v2 = vD - vC,
191 vCross01 = Cross(v0,v1),
192 vCross12 = Cross(v1,v2),
193 vCross0112 = Cross(vCross01, vCross12);
194 return std::atan2(Dot(vCross0112, v1.Normalized()), Dot(vCross01, vCross12));
195 // ^- confused yet? 8)
196 }
197
198
FMeasurePlaneAngle(int iAt_,int jAt_,int kAt_,int lAt_,FDocument * pDocument_)199 FMeasurePlaneAngle::FMeasurePlaneAngle(int iAt_, int jAt_, int kAt_, int lAt_, FDocument *pDocument_)
200 : FMeasure(pDocument_,QString::fromWCharArray(L"\u00b0"),2,180./M_PI), m_iAt(iAt_), m_jAt(jAt_), m_kAt(kAt_), m_lAt(lAt_)
201 {}
202
Name() const203 QString FMeasurePlaneAngle::Name() const
204 {
205 return QString(QString::fromWCharArray(L"\u03d5(%1 | %2 | %3 | %4)")).arg(m_pDocument->AtomLabel(m_iAt), m_pDocument->AtomLabel(m_jAt), m_pDocument->AtomLabel(m_kAt), m_pDocument->AtomLabel(m_lAt));
206 }
207
208
MakeValues(FMeasureSet & FrameValues,FFrameMeasurePtrList & Frames) const209 void FMeasurePlaneAngle::MakeValues(FMeasureSet &FrameValues, FFrameMeasurePtrList &Frames) const
210 {
211 FrameValues.clear();
212 FrameValues.reserve(Frames.size());
213 // foreach(FFrameMeasurePtrList::value_type const *itFrame, Frames) {
214 FFrameMeasurePtrList::const_iterator itFrame;
215 _for_each(itFrame, Frames) {
216 ct::FAtomSet *pAtoms = (*itFrame)->pGetAtoms();
217 if (pAtoms && size_t(m_iAt) < pAtoms->size() && size_t(m_jAt) < pAtoms->size()) {
218 ct::FVector3
219 vI = (*pAtoms)[size_t(m_iAt)].vPos,
220 vJ = (*pAtoms)[size_t(m_jAt)].vPos,
221 vK = (*pAtoms)[size_t(m_kAt)].vPos,
222 vL = (*pAtoms)[size_t(m_lAt)].vPos;
223 FrameValues.push_back(m_AuToOut * Dihedral(vI, vJ, vK, vL));
224 } else {
225 FrameValues.push_back(0);
226 }
227 }
228 }
229
230
231
232
FMeasureFrameGradient(FDocument * pDocument_)233 FMeasureFrameGradient::FMeasureFrameGradient(FDocument *pDocument_)
234 : FMeasure(pDocument_,"mgu",6,1.)
235 {
236 // mgu: mystery gradient units (different programs write different units into
237 // the gradient fields of .xyz files, and particularly what Turbomole was
238 // doing... no idea.)
239 }
240
MakeValues(FMeasureSet & FrameValues,FFrameMeasurePtrList & Frames) const241 void FMeasureFrameGradient::MakeValues(FMeasureSet &FrameValues, FFrameMeasurePtrList &Frames) const
242 {
243 FrameValues.clear();
244 FrameValues.reserve(Frames.size());
245 // foreach(FFrameMeasurePtrList::value_type const *itFrame, Frames) {
246 FFrameMeasurePtrList::const_iterator itFrame;
247 _for_each(itFrame, Frames) {
248 // ct::FAtomSet
249 // *pAtoms = (*itFrame)->pGetAtoms();
250 // double
251 // fGrad = 0.;
252 // if (pAtoms) {
253 // for (size_t iAt = 0; iAt < pAtoms->size(); ++ iAt)
254 // fGrad += ct::LengthSq((*pAtoms)[iAt].vGrad);
255 // }
256 // FrameValues.push_back(sqrt(fGrad));
257 FrameValues.push_back((*itFrame)->GetGradient());
258 }
259 }
260
Name() const261 QString FMeasureFrameGradient::Name() const
262 {
263 return QString::fromUtf8("|grad E|");
264 }
265
266
FMeasureFrameEnergy(FDocument * pDocument_)267 FMeasureFrameEnergy::FMeasureFrameEnergy(FDocument *pDocument_)
268 : FMeasure(pDocument_,"Eh",8,1.)
269 {
270 }
271
MakeValues(FMeasureSet & FrameValues,FFrameMeasurePtrList & Frames) const272 void FMeasureFrameEnergy::MakeValues(FMeasureSet &FrameValues, FFrameMeasurePtrList &Frames) const
273 {
274 FrameValues.clear();
275 FrameValues.reserve(Frames.size());
276 // foreach(FFrameMeasurePtrList::value_type const *itFrame, Frames) {
277 FFrameMeasurePtrList::const_iterator itFrame;
278 _for_each(itFrame, Frames) {
279 ct::FAtomSet
280 *pAtoms = (*itFrame)->pGetAtoms();
281 double
282 fEnergy = 0.;
283 if (pAtoms)
284 fEnergy = pAtoms->GetLastEnergy();
285 FrameValues.push_back(fEnergy);
286 }
287 }
288
Name() const289 QString FMeasureFrameEnergy::Name() const
290 {
291 return QString::fromUtf8("Energy");
292 }
293
294
FMeasureFrameId(FDocument * pDocument_)295 FMeasureFrameId::FMeasureFrameId(FDocument *pDocument_)
296 : FMeasure(pDocument_,"",0,1.)
297 {
298 }
299
MakeValues(FMeasureSet & FrameValues,FFrameMeasurePtrList & Frames) const300 void FMeasureFrameId::MakeValues(FMeasureSet &FrameValues, FFrameMeasurePtrList &Frames) const
301 {
302 FrameValues.resize(Frames.size());
303 for (size_t i = 0; i < Frames.size(); ++ i)
304 // FrameValues[i] = double(i);
305 FrameValues[i] = m_pDocument->iFrameId(&*Frames[i]);
306 }
307
Name() const308 QString FMeasureFrameId::Name() const
309 {
310 return QString("#Frame");
311 }
312
313
314
FDocumentMeasures(FDocument * pDocument_,QObject * Parent_)315 FDocumentMeasures::FDocumentMeasures(FDocument *pDocument_, QObject *Parent_)
316 : FBase(Parent_), m_pDocument(pDocument_)
317 {
318 AddMeasure(new FMeasureFrameId(m_pDocument));
319 AddMeasure(new FMeasureFrameEnergy(m_pDocument));
320 AddMeasure(new FMeasureFrameGradient(m_pDocument));
321
322 // note: if this doesn't work, the Q_OBJECT is missing. Would complain about non-existent slots
323 // in the base class.
324 ConnectForwardSignals();
325 }
326
ConnectForwardSignals()327 void FDocumentMeasures::ConnectForwardSignals()
328 {
329 // forward those things... to deal with newly inserted frames etc.
330 connect(m_pDocument, SIGNAL(layoutAboutToBeChanged()), this, SLOT(parentLayoutAboutToBeChanged()));
331 connect(m_pDocument, SIGNAL(layoutChanged()), this, SLOT(parentLayoutChanged()));
332 }
333
~FDocumentMeasures()334 FDocumentMeasures::~FDocumentMeasures()
335 {
336 }
337
338
rowCount(const QModelIndex & parent) const339 int FDocumentMeasures::rowCount(const QModelIndex &parent) const
340 {
341 return m_pDocument->columnCount();
342 IR_SUPPRESS_UNUSED_WARNING(parent);
343 }
344
columnCount(const QModelIndex & parent) const345 int FDocumentMeasures::columnCount(const QModelIndex &parent) const
346 {
347 return static_cast<int>(m_List.size());
348 IR_SUPPRESS_UNUSED_WARNING(parent);
349 }
350
headerData(int section,Qt::Orientation orientation,int role) const351 QVariant FDocumentMeasures::headerData(int section, Qt::Orientation orientation, int role) const
352 {
353 // IvEmit("HeaderData: Section = %1 orientation = %2 role = %3", section, int(orientation), role);
354 if (role == Qt::DisplayRole && orientation == Qt::Vertical) {
355 FFrame
356 *pFrame = m_pDocument->GetFrame(section, false);
357 if (pFrame == 0)
358 return QVariant("#UNK");
359 return IvFmt("Frame %1", section);
360 }
361 if (role == Qt::DisplayRole && orientation == Qt::Horizontal) {
362 FMeasure const
363 *pMeasure = GetMeasure(int(section));
364 if (pMeasure == 0)
365 return QVariant("#UNK");
366 QString
367 UnitName = pMeasure->UnitName();
368 if (UnitName.isEmpty())
369 return pMeasure->Name();
370 else
371 return IvFmt("%1 [%2]", pMeasure->Name(), UnitName);
372 }
373 if ( role == Qt::FontRole ) {
374 QFont CaptionFont;
375 CaptionFont.setBold(true);
376 return CaptionFont;
377 }
378 return QVariant();
379 }
380
data(const QModelIndex & index,int role) const381 QVariant FDocumentMeasures::data(const QModelIndex &index, int role) const
382 {
383 if (role == Qt::DisplayRole) {
384 FMeasure const
385 *pMeasure = GetMeasure(index);
386 FFrame
387 *pFrame = m_pDocument->GetFrame(index.row(),false);
388 if (pFrame == 0 || pMeasure == 0)
389 return QVariant("#UNK");
390 return QVariant(pMeasure->MeasureFrame(pFrame,FMeasure::FORMAT_ValueOnly));
391 }
392 if (role == Qt::TextAlignmentRole)
393 return QVariant(Qt::AlignRight);
394 return QVariant();
395 }
396
removeColumns(int column,int count,const QModelIndex & parent)397 bool FDocumentMeasures::removeColumns(int column, int count, const QModelIndex &parent)
398 {
399 if (count < 0 || column + count >= columnCount()) {
400 IV_NOTIFY(NOTIFY_Warning, "Attempted to remove non-existent measurement rows.");
401 return false;
402 }
403 beginRemoveColumns(parent, column, column + count - 1);
404 FMeasureList::iterator
405 // itFirst = std::next(m_List.begin(), column),
406 // itLast = std::next(itFirst, count);
407 itFirst = m_List.begin() + column,
408 itLast = itFirst + count;
409 m_List.erase(itFirst, itLast);
410 endRemoveColumns();
411 return true;
412 }
413
AddMeasure(FMeasurePtr pMeasure)414 void FDocumentMeasures::AddMeasure(FMeasurePtr pMeasure)
415 {
416 beginInsertColumns(QModelIndex(), rowCount(), rowCount()); // 'last' is inclusive!.
417 m_List.push_back(pMeasure);
418 endInsertColumns();
419 }
420
GetMeasure(QModelIndex const & index)421 FMeasure *FDocumentMeasures::GetMeasure(QModelIndex const &index)
422 {
423 FFrame
424 *pFrame = m_pDocument->GetFrame(index.row(),false);
425 if (pFrame == 0)
426 return 0;
427 return GetMeasure(int(index.column()));
428 }
429
GetMeasure(int iColumn)430 FMeasure *FDocumentMeasures::GetMeasure(int iColumn)
431 {
432 if (iColumn < 0 || iColumn >= columnCount())
433 return 0;
434 return &*m_List[size_t(iColumn)];
435 }
436
parentLayoutAboutToBeChanged()437 void FDocumentMeasures::parentLayoutAboutToBeChanged()
438 {
439 emit layoutAboutToBeChanged();
440 }
441
parentLayoutChanged()442 void FDocumentMeasures::parentLayoutChanged()
443 {
444 emit layoutChanged();
445 }
446
447
FTablesForm(FDocument * pDocument_,QWidget * pParent_)448 FTablesForm::FTablesForm(FDocument *pDocument_, QWidget *pParent_)
449 : FBase(pParent_),
450 ui(new Ui::TablesForm),
451 m_pDocument(pDocument_)
452 {
453 ui->setupUi(this);
454 ui->tableView_Values->setModel(m_pDocument->GetMeasures());
455
456 #if QT_VERSION >= 0x050000
457 // ui->tableView_Values->horizontalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents);
458 ui->tableView_Values->verticalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents);
459 #else
460 // qt5 doc's say there is a compatibiltiy layer for this.. but it doesn't seem to exist
461 // in my windows qt 5.3.2 version.
462 // ui->tableView_Values->horizontalHeader()->setResizeMode(QHeaderView::ResizeToContents);
463 ui->tableView_Values->verticalHeader()->setResizeMode(QHeaderView::ResizeToContents);
464 #endif
465 ui->tableView_Values->resizeColumnsToContents();
466
467 // FTransposeProxyModel
468 // *pProxyModel = new FTransposeProxyModel(this);
469 // pProxyModel->setSourceModel(m_pDocument->GetMeasures());
470 // ui->tableView_Values->setModel(pProxyModel);
471 }
472