3
* $Id: ecgstudy.cpp 3763 2011-04-25 12:07:55Z carlos $
6
* Copyright 2008-10 MetaEmotion S.L. All rights reserved.
7
* http://ginkgo-cadx.com
9
* This file is licensed under LGPL v3 license.
10
* See License.txt for details
14
//#define _GINKGO_TRACE
17
#include <wx/xml/xml.h>
19
#include <wx/filename.h>
20
#include <wx/confbase.h>
21
#include <wx/mstream.h>
22
#include <wx/tokenzr.h>
24
#include <api/globals.h>
25
//#include <api/filename.h>
26
#include <api/icontroladorherramientas.h>
27
#include <api/ientorno.h>
28
#include <main/controllers/controladorlog.h>
30
#include <api/idicommanager.h>
31
#include <api/idicomizador.h>
32
#include <api/icontroladorcarga.h>
33
#include <api/imodelointegracion.h>
34
#include <api/icontroladorhistorial.h>
35
#include <api/internacionalizacion.h>
39
#include <vtkPointData.h>
40
#include <vtkImageData.h>
46
const char* HemodynamicWaveformStorage = "1.2.840.10008.5.1.4.1.1.9.2.1";
47
const char* TwelveLeadECGWaveformStorage = "1.2.840.10008.5.1.4.1.1.9.1.1";
48
const char* GeneralECGWaveformStorage = "1.2.840.10008.5.1.4.1.1.9.1.2";
52
const char* MediaStorageSOPClassUID = "0002|0002";
53
const char* WaveformOriginality = "003a|0004";
54
const char* NumberOfWaveformChannels = "003a|0005";
55
const char* NumberOfWaveformSamples = "003a|0010";
56
const char* SamplingFrequency = "003a|001a";
57
const char* MultiplexGroupLabel = "003a|0020";
58
const char* ChannelDefinitionSequence = "003a|0200";
59
const char* WaveformChannelNumber = "003a|0202";
60
const char* ChannelLabel = "003a|0203";
61
const char* ChannelStatus = "003a|0205";
62
const char* ChannelSourceSequence = "003a|0208";
63
const char* ChannelSourceModifiersSequence = "003a|0209";
64
const char* SourceWaveformSequence = "003a|020a";
65
const char* ChannelDerivationDescription = "003a|020c";
66
const char* ChannelSensitivity = "003a|0210";
67
const char* ChannelSensitivityUnitsSequence = "003a|0211";
68
const char* ChannelSensitivityCorrectionFactor = "003a|0212";
69
const char* ChannelBaseline = "003a|0213";
70
const char* ChannelTimeSkew = "003a|0214";
71
const char* ChannelSampleSkew = "003a|0215";
72
const char* ChannelOffset = "003a|0218";
73
const char* WaveformBitsStored = "003a|021a";
74
const char* FilterLowFrequency = "003a|0220";
75
const char* FilterHighFrequency = "003a|0221";
76
const char* NotchFilterFrequency = "003a|0222";
77
const char* NotchFilterBandwidth = "003a|0223";
78
const char* WaveformDataDisplayScale = "003a|0230";
79
const char* WaveformDisplayBkgCIELabValue = "003a|0231";
80
const char* WaveformPresentationGroupSequence = "003a|0240";
81
const char* PresentationGroupNumber = "003a|0241";
82
const char* ChannelDisplaySequence = "003a|0242";
83
const char* ChannelRecommendDisplayCIELabValue = "003a|0244";
84
const char* ChannelPosition = "003a|0245";
85
const char* DisplayShadingFlag = "003a|0246";
86
const char* FractionalChannelDisplayScale = "003a|0247";
87
const char* AbsoluteChannelDisplayScale = "003a|0248";
88
const char* MultiplexAudioChannelsDescrCodeSeq = "003a|0300";
89
const char* ChannelIdentificationCode = "003a|0301";
90
const char* ChannelMode = "003a|0302";
92
const char* WaveFormSequence = "5400|0100";
93
const char* ChannelMinimumValue = "5400|0110";
94
const char* ChannelMaximumValue = "5400|0112";
95
const char* WaveformBitsAllocated = "5400|1004";
96
const char* WaveformSampleInterpretation = "5400|1006";
97
const char* WaveformPaddingValue = "5400|100a";
98
const char* WaveformData = "5400|1010";
100
const char* AnnotationSequence = "0040|b020";
101
const char* UnformattedTextValue = "0070|0006";
102
const char* AnnotationGroupNumber = "0040|a180";
103
const char* ReferencedChannels = "0040|a0b0";
104
const char* TemporalRangeType = "0040|a130";
105
const char* RefSamplePositions = "0040|a132";
106
const char* NumericValue = "0040|a30a";
108
const char* ConceptCodeSequence = "0040|a168";
109
const char* ConceptNameCodeSequence = "0040|a043";
110
const char* MeasurementsUnitsCodeSequence = "0040|08ea";
111
const char* CodingSchemeDesignator = "0008|0102";
112
const char* CodingValue ="0008|0100";
113
const char* CodingSchemeVersion = "0008|0103";
116
template<class T> void Get(const std::string& str, T& val)
118
std::istringstream is(str);
122
typedef std::vector<std::pair<std::string, std::string> > TVectorPairStrings;
123
typedef std::vector<std::string> TVectorStrings;
124
typedef std::map<int,TVectorStrings > TMapVectorStrings;
126
bool IsCodeSequence(GIL::DICOM::TipoJerarquia& base, const std::string& tag, std::string& codeValue, std::string codingSchemeDesignator, std::string codingSchemeVersion)
128
GIL::DICOM::TipoJerarquia* seq = base.buscar_secuencia(tag);
129
if (seq != NULL && seq->items.size() > 0) {
130
if (seq->items.front().getTag(TAGS::CodingSchemeDesignator) == codingSchemeDesignator || seq->items.front().getTag(TAGS::CodingSchemeVersion) == codingSchemeVersion) {
131
seq->items.front().getTag(TAGS::CodingValue, codeValue);
138
int calcNrOfValues(const TMapVectorStrings& vals)
142
for (TMapVectorStrings::const_iterator it = vals.begin(); it != vals.end(); ++it) {
143
for (TVectorStrings::const_iterator itV = (*it).second.begin(); itV != (*it).second.end(); ++itV) {
153
TMapVectorStrings GetValues(GIL::DICOM::TipoJerarquia* sequence, TVectorPairStrings& items, TVectorPairStrings& units, std::vector<int>& rwc, bool special)
155
TMapVectorStrings result;
157
TMapVectorStrings sl;
159
for (GIL::DICOM::TipoJerarquia::ListaJerarquias::reverse_iterator itAnnotations = sequence->items.rbegin(); itAnnotations != sequence->items.rend(); ++itAnnotations)
161
GIL::DICOM::TipoJerarquia& base = (*itAnnotations);
162
std::string itemName;
164
if (IsCodeSequence(base, TAGS::ConceptNameCodeSequence, itemName, "SCPECG", "1.3"))
168
for (;nr < (int)items.size();nr++) {
169
if (items[nr].first == itemName) {
174
if (nr == items.size())
179
Get(base.getTag(TAGS::AnnotationGroupNumber),groupNr);
181
if (units[nr].second == "")
183
if (units[nr].first == base.getTag(TAGS::TemporalRangeType))
184
val = base.getTag(TAGS::RefSamplePositions);
186
else if (IsCodeSequence(base, TAGS::MeasurementsUnitsCodeSequence, val, "UCUM", "1.4"))
188
val = base.getTag(TAGS::NumericValue);
191
/*int[] tempRWC = ds.GetInts(Tags.RefWaveformChannels);
195
&& (tempRWC.Length == rwc.Length))
197
for (int k=0;k < rwc.Length;k++)
198
if (tempRWC[k] != rwc[k])
201
string[] temp = null;
203
if (sl.Contains(groupNr))
204
temp = (string[]) sl[groupNr];
207
temp = new string[items.GetLength(1)];
209
sl.Add(groupNr, temp);
214
if (val != "" && groupNr>=0) {
215
if (sl.find(groupNr) == sl.end()) {
216
sl[groupNr] = TVectorStrings(items.size());
218
sl[groupNr][nr] = val;
225
if (special && sl.size() >= 2
226
&& (items.size() < 64))
228
int temp1 = items.size();
229
unsigned long a = 0, b = 0;
231
TVectorStrings& temp2 = sl.begin()->second;
233
for (TVectorStrings::iterator it = temp2.begin(); it != temp2.end(); ++it,++i) {
239
TMapVectorStrings::iterator itSecond = sl.begin();
241
TVectorStrings& temp3 = itSecond->second;
243
for (TVectorStrings::iterator it = temp3.begin(); it != temp3.end(); ++it,++i) {
249
if ((a ^ b) == (a + b))
251
for (int i=0;i < temp1;i++) {
252
if (temp2[i] != "") {
257
sl.erase(sl.begin());
261
for (TMapVectorStrings::iterator it = sl.begin(); it != sl.end(); it++)
263
result[(*it).first] = TVectorStrings();
265
for (TVectorStrings::iterator itStr = (*it).second.begin(); itStr != (*it).second.end(); ++itStr)
266
result[(*it).first].push_back((*itStr));
267
std::ostringstream ostr;
269
result [(*it).first].push_back(ostr.str());
276
///////////////////////////////////////////////////////////////////////
277
void GNKVisualizator::ChannelInfo::SetLead(const std::string& codingSchemeDesignator, const std::string& codingValue)
279
if (codingSchemeDesignator == "SCPECG")
281
wxStringTokenizer tkz(wxString::FromUTF8(codingValue.c_str()), wxT("-"));
282
//code is the last token
283
wxString code(wxT("0"));
284
while (tkz.HasMoreTokens()) {
285
code = tkz.GetNextToken();
288
if (code.ToLong(&lead) && lead > 0 && lead < 185) {
289
this->LeadType = (TLeadType)(lead);
291
} else if (codingSchemeDesignator == "MDC") {
293
const char* mdc0[] = { "MDC_ECG_LEAD_CONFIG", "MDC_ECG_LEAD_I", "MDC_ECG_LEAD_II", "MDC_ECG_LEAD_V1", "MDC_ECG_LEAD_V2", "MDC_ECG_LEAD_V3", "MDC_ECG_LEAD_V4", "MDC_ECG_LEAD_V5", "MDC_ECG_LEAD_V6",
294
"MDC_ECG_LEAD_V7", "MDC_ECG_LEAD_V2R", "MDC_ECG_LEAD_V3R", "MDC_ECG_LEAD_V4R", "MDC_ECG_LEAD_V5R", "MDC_ECG_LEAD_V6R", "MDC_ECG_LEAD_V7R", "MDC_ECG_LEAD_X", "MDC_ECG_LEAD_Y", "MDC_ECG_LEAD_Z",
295
"MDC_ECG_LEAD_CC5", "MDC_ECG_LEAD_CM5", "MDC_ECG_LEAD_LA", "MDC_ECG_LEAD_RA", "MDC_ECG_LEAD_LL", "MDC_ECG_LEAD_fI", "MDC_ECG_LEAD_fE", "MDC_ECG_LEAD_fC", "MDC_ECG_LEAD_fA", " MDC_ECG_LEAD_fM",
296
"MDC_ECG_LEAD_fF", "MDC_ECG_LEAD_fH", "MDC_ECG_LEAD_dI", "MDC_ECG_LEAD_dII", "MDC_ECG_LEAD_dV1", "MDC_ECG_LEAD_dV2", "MDC_ECG_LEAD_dV3", "MDC_ECG_LEAD_dV4", "MDC_ECG_LEAD_dV5", "MDC_ECG_LEAD_dV6"
298
for (int i = 0; i< 39; ++i) {
299
if (codingValue == mdc0[i]) {
300
this->LeadType = (TLeadType)i;
304
const char* mdc61[] = {"MDC_ECG_LEAD_III", "MDC_ECG_LEAD_aVR", "MDC_ECG_LEAD_aVL", "MDC_ECG_LEAD_aVF", "MDC_ECG_LEAD_aVRneg", "MDC_ECG_LEAD_V8", "MDC_ECG_LEAD_V9", "MDC_ECG_LEAD_V8R", "MDC_ECG_LEAD_V9R",
305
"MDC_ECG_LEAD_D", "MDC_ECG_LEAD_A", "MDC_ECG_LEAD_J", "MDC_ECG_LEAD_Defib", " MDC_ECG_LEAD_Extern", "MDC_ECG_LEAD_A1", "MDC_ECG_LEAD_A2", "MDC_ECG_LEAD_A3", "MDC_ECG_LEAD_A4"
307
for (int i = 0; i< 18; ++i) {
308
if (codingValue == mdc61[i]) {
309
this->LeadType = (TLeadType)(i+61);
313
const char* mdc86[] = {"MDC_ECG_LEAD_C", "MDC_ECG_LEAD_V", "MDC_ECG_LEAD_VR", "MDC_ECG_LEAD_VL", "MDC_ECG_LEAD_VF", "MDC_ECG_LEAD_MCL", "MDC_ECG_LEAD_MCL1", "MDC_ECG_LEAD_MCL2", "MDC_ECG_LEAD_MCL3",
314
"MDC_ECG_LEAD_MCL4", " MDC_ECG_LEAD_MCL5", "MDC_ECG_LEAD_MCL6", "MDC_ECG_LEAD_CC", "MDC_ECG_LEAD_CC1", "MDC_ECG_LEAD_CC2", "MDC_ECG_LEAD_CC3", "MDC_ECG_LEAD_CC4", "MDC_ECG_LEAD_CC6", "MDC_ECG_LEAD_CC7",
315
"MDC_ECG_LEAD_CM", "MDC_ECG_LEAD_CM1", "MDC_ECG_LEAD_CM2", "MDC_ECG_LEAD_CM3", "MDC_ECG_LEAD_CM4", "MDC_ECG_LEAD_CM6", "MDC_ECG_LEAD_dIII", " MDC_ECG_LEAD_daVR", "MDC_ECG_LEAD_daVL", "MDC_ECG_LEAD_daVF"
317
for (int i = 0; i< 29; ++i) {
318
if (codingValue == mdc86[i]) {
319
this->LeadType = (TLeadType)(i+86);
323
const char* mdc121[] = {"MDC_ECG_LEAD_CM7", "MDC_ECG_LEAD_CH5", "MDC_ECG_LEAD_CS5", "MDC_ECG_LEAD_CB5", "MDC_ECG_LEAD_CR5", "MDC_ECG_LEAD_ML", "MDC_ECG_LEAD_AB1", "MDC_ECG_LEAD_AB2", "MDC_ECG_LEAD_AB3",
324
"MDC_ECG_LEAD_AB4", "MDC_ECG_LEAD_ES", "MDC_ECG_LEAD_AS", "MDC_ECG_LEAD_AI", "MDC_ECG_LEAD_S"
326
for (int i = 0; i< 14; ++i) {
327
if (codingValue == mdc121[i]) {
328
this->LeadType = (TLeadType)(i+121);
332
const char* mdc147[] = {"MDC_ECG_LEAD_RL", "MDC_ECG_LEAD_CV5RL", "MDC_ECG_LEAD_CV6LL", "MDC_ECG_LEAD_CV6LU", "MDC_ECG_LEAD_V10"
334
for (int i = 0; i< 5; ++i) {
335
if (codingValue == mdc147[i]) {
336
this->LeadType = (TLeadType)(i+147);
341
LOG_WARN("EGCStudy", "Unsupported coding scheme designator: " << codingSchemeDesignator);
345
std::string GNKVisualizator::ChannelInfo::GetTitle() const
347
const char* leadStrings[] = {"Unknown", "I", "II", "V1", "V2", "V3", "V4", "V5", "V6", "V7", "V2R", "V3R", "V4R", "V5R", "V6R", "V7R", "X", "Y", "Z",
348
"CC5", "CM5", "LA", "RA", "LL", "fI", "fE", "fC", "fA", "fM", "fF", "fH", "dI", "dII", "dV1", "dV2", "dV3", "dV4", "dV5", "dV6",
349
"dV7", "dV2R", "dV3R", "dV4R", "dV5R", "dV6R", "dV7R", "dX", "dY", "dZ", "dCC5", "dCM5", "dLA", "dRA", "dLL", "dfI", "dfE",
350
"dfC", "dfA", "dfM", "dfF", "dfH", "III", "aVR", "aVL", "aVF", "aVRneg", "V8", "V9", "V8R", "V9R", "D", "A", "J", "Defib",
351
"Extern", "A1", "A2", "A3", "A4", "dV8", "dV9", "dV8R", "dV9R", "dD", "dA", "dJ", "Chest", "V", "VR", "VL", "VF", "MCL", "MCL1",
352
"MCL2", "MCL3", "MCL4", "MCL5", "MCL6", "CC", "CC1", "CC2", "CC3", "CC4", "CC6", "CC7", "CM", "CM1", "CM2", "CM3", "CM4", "CM6",
353
"dIII", "daVR", "daVL", "daVF", "daVRneg", "dChest", "dV", "dVR", "dVL", "dVF", "CM7", "CH5", "CS5", "CB5", "CR5", "ML", "AB1",
354
"AB2", "AB3", "AB4", "ES", "AS", "AI", "S", "dDefib", "dExtern", "dA1", "dA2", "dA3", "dA4", "dMCL1", "dMCL2", "dMCL3",
355
"dMCL4", "dMCL5", "dMCL6", "RL", "CV5RL", "CV6LL", "CV6LU", "V10", "dMCL", "dCC", "dCC1", "dCC2", "dCC3", "dCC4", "dCC6",
356
"dCC7", " dCM", "dCM1", "dCM2", "dCM3", "dCM4", "dCM6", "dCM7", "dCH5", "dCS5", "dCB5", "dCR5", "dML", "dAB1", "dAB2", "dAB3",
357
"dAB4", "dES", "dAS", "dAI", "dS", "dRL", "dCV5RL", "dCV6LL", "dCV6LU", "dV10"};
358
return std::string(leadStrings[(int)LeadType]);
361
void GNKVisualizator::ChannelInfo::SetUnitsValue(const std::string& unitsvalue) {
362
UnitsValue = unitsvalue;
363
if (UnitsValue == "mV") {
365
} else if (UnitsValue == "uV") {
367
} else if (UnitsValue == "MV" ) {
368
Multiplier = 100000000000.0;
369
} else if (UnitsValue == "kV") {
370
Multiplier = 100000000.0;
371
} else if (UnitsValue == "V") {
372
Multiplier = 100000.0;
373
} else if (UnitsValue == "dV") {
374
Multiplier = 10000.0;
375
} else if (UnitsValue == "cV") {
378
std::ostringstream ostr;
379
ostr << _Std("We are working to support ") << UnitsValue;
380
throw GNC::GCS::ControladorCargaException(ostr.str(), "ECGStudy");
385
///////////////////////////////////////////////////////////////////////
387
GNKVisualizator::ECGStudy::ECGStudy(){
388
GTRACE(">> ECGStudy::ECGStudy()" << this);
389
GTRACE("<< ECGStudy::ECGStudy()" << this);
392
GNKVisualizator::ECGStudy::~ECGStudy(){
393
GTRACE(">> ECGStudy::~ECGStudy()" << this);
395
GTRACE("<< ECGStudy::~ECGStudy()" << this);
399
void GNKVisualizator::ECGStudy::InicializarContextoEstudio(std::vector<std::string>& rutas, const std::string uidEstudioDiagnostico, GNC::GCS::IContextoEstudio::TModoFuncionamiento modoFuncionamiento)
401
GNC::GCS::IContextoEstudio::InicializarContextoEstudio(rutas,uidEstudioDiagnostico, modoFuncionamiento);
403
for (int i = 0; i < (int)rutas.size(); ++i) {
404
ECGFiles.push_back(NULL);
408
void GNKVisualizator::ECGStudy::SetIndexOfActualMultiplexGroup(int index)
411
ECGFiles[IndiceFicheroActivo]->SetIndexOfActualMultiplexGroup(index);
414
GNKVisualizator::ECGStudy::TListChannelInfo& GNKVisualizator::ECGStudy::GetListOfChannels()
417
return ECGFiles[IndiceFicheroActivo]->GetListOfChannels();
420
std::list<std::string> GNKVisualizator::ECGStudy::GetLabelOfMultiplexGroups()
423
return ECGFiles[IndiceFicheroActivo]->GetLabelOfMultiplexGroups();
426
const std::string GNKVisualizator::ECGStudy::GetGlobalMeasurement()
429
std::ostringstream ostr;
430
if (ECGFiles[IndiceFicheroActivo]->globalMeasurements.IsValid()) {
431
GNKVisualizator::GlobalMeasurements& mes = (*ECGFiles[IndiceFicheroActivo]->globalMeasurements);
433
int ventRate = (mes.getVentRate() == MeasurementNoValue) ? 0 : (int) mes.getVentRate(),
434
PRint = (mes.getPRint() == MeasurementNoValue) ? 0 : (int) mes.measurment[0]->PRint(),
435
QRSdur = (mes.getQRSdur() == MeasurementNoValue) ? 0 : (int) mes.measurment[0]->QRSdur(),
436
QT = (mes.getQTdur() == MeasurementNoValue) ? 0 : (int) mes.measurment[0]->QTdur(),
437
QTc = (mes.getQTc() == MeasurementNoValue) ? 0 : (int) mes.getQTc();
439
ostr << _Std("Vent rate: ");
441
ostr << _Std(" BPM") << std::endl;
443
ostr << _Std("PR int: ");
445
ostr << _Std(" ms") << std::endl;
447
ostr << _Std("QRS dur: ");
449
ostr << _Std(" ms") << std::endl;
451
ostr << _Std("QT\\QTc: ");
452
ostr << QT << "/" << QTc;
453
ostr << _Std(" ms") << std::endl;
455
ostr << _Std("P-R-T axes: ");
456
if (mes.measurment[0]->Paxis != MeasurementNoAxisValue) {
457
ostr << mes.measurment[0]->Paxis;
462
if (mes.measurment[0]->QRSaxis != MeasurementNoAxisValue) {
463
ostr << mes.measurment[0]->QRSaxis;
468
if (mes.measurment[0]->Taxis != MeasurementNoAxisValue) {
469
ostr << mes.measurment[0]->Taxis;
474
ostr << _Std("Measurements not found");
479
const std::string& GNKVisualizator::ECGStudy::GetDiagnosis()
482
return ECGFiles[IndiceFicheroActivo]->GetDiagnosis();
485
void GNKVisualizator::ECGStudy::LoadChannels()
487
if (!ECGFiles[IndiceFicheroActivo].IsValid())
489
GnkPtr<TECGFile> ecgFile(new TECGFile);
490
ECGFiles[IndiceFicheroActivo] = ecgFile;
492
GnkPtr<GIL::DICOM::TipoJerarquia> base(new GIL::DICOM::TipoJerarquia());
493
GIL::DICOM::IDICOMManager* pDICOMManager = Entorno->GetControladorImportacionPACS()->CrearInstanciaDeDICOMManager();
495
GIL::DICOM::TipoMetaInfo metaInfo;
497
pDICOMManager->CargarMetaInfo(GetRutaDeImagenActiva(), metaInfo);
499
std::string sopClassUID = metaInfo.getTag(TAGS::MediaStorageSOPClassUID);
501
GIL::DICOM::TagPrivadoUndefined tag;
503
if (sopClassUID == UIDS::GeneralECGWaveformStorage ||
504
sopClassUID == UIDS::HemodynamicWaveformStorage ||
505
sopClassUID == UIDS::TwelveLeadECGWaveformStorage )
508
pDICOMManager->CargarFichero(GetRutaDeImagenActiva(), *base, false);
509
pDICOMManager->FindTag(0x5400, 0x1010, tag);
511
Entorno->GetControladorImportacionPACS()->LiberarInstanciaDeDICOMManager(pDICOMManager);
514
Entorno->GetControladorImportacionPACS()->LiberarInstanciaDeDICOMManager(pDICOMManager);
518
GIL::DICOM::TipoJerarquia* waveformSeq = base->buscar_secuencia(TAGS::WaveFormSequence);
522
double samplingFreq = 0.0;
523
short paddingValue = 0;
525
std::string groupLabel;
527
std::string waveFormSampleInterpretation;
529
for (GIL::DICOM::TipoJerarquia::ListaJerarquias::reverse_iterator itSequences = waveformSeq->items.rbegin(); itSequences != waveformSeq->items.rend(); ++itSequences)
532
GIL::DICOM::TipoJerarquia& wf = (*itSequences);
533
ecgFile->Groups.push_back(TMultiplexGroup());
534
TMultiplexGroup& group = ecgFile->Groups.back();
536
Get(wf.getTag(TAGS::NumberOfWaveformChannels), numChannels);
537
Get(wf.getTag(TAGS::NumberOfWaveformSamples), numSamples);
538
Get(wf.getTag(TAGS::SamplingFrequency), samplingFreq);
539
//FIXME mal no pilla bien el padding value porque es de tipo ox
540
Get(wf.getTag(TAGS::WaveformPaddingValue), paddingValue);
541
wf.getTag(TAGS::WaveformOriginality, orig);
542
wf.getTag(TAGS::MultiplexGroupLabel, groupLabel);
543
Get(wf.getTag(TAGS::WaveformBitsAllocated), bitsAllocated);
544
wf.getTag(TAGS::WaveformSampleInterpretation, waveFormSampleInterpretation);
545
if (bitsAllocated != 16 || waveFormSampleInterpretation != "SS") {
546
LOG_ERROR("ECGStudy", "We are unnable to interpret bitsAllocated=" << bitsAllocated << " waveFormSampleInterpretation=" << waveFormSampleInterpretation);
547
throw GNC::GCS::ControladorCargaException(_Std("ECG format not supported"), "ECGStudy");
550
if (groupLabel != "") {
551
group.Label = groupLabel;
556
GIL::DICOM::TipoJerarquia* channel_def_seq = wf.buscar_secuencia(TAGS::ChannelDefinitionSequence);
558
if (channel_def_seq->items.size() == (unsigned int) numChannels) {
561
for (GIL::DICOM::TipoJerarquia::ListaJerarquias::reverse_iterator it = channel_def_seq->items.rbegin(); it != channel_def_seq->items.rend(); it++, i++) {
562
group.Channels.push_back(GNKVisualizator::ChannelInfo());
564
GIL::DICOM::TipoJerarquia& channel_def = (*it);
566
//>> SQ Items (1): (003A,0208) - Channel Source Sequence
567
// > (0008|0104, LO, "Lead I") # 0x6 - Code Meaning OK
568
// > (003A|0210, DS, "0.00122") # 0x8 - Channel sensitivity OK
571
GIL::DICOM::TipoJerarquia* channel_src_seq = channel_def.buscar_secuencia(TAGS::ChannelSourceSequence);
573
//>> SQ Items (1): (003A,0211) - Channel sensitivity units
574
// > (0008|0100, SH, "mV") # 0x2 - Code Value OK
575
// > (0008|0104, LO, "millivolt") # 0xA - Code Meaning OK
576
// > (003A|0212, DS, "1") # 0x2 - Sensitivity correction factor OK
577
// > (003A|0213, DS, "0") # 0x2 - Channel baseline OK
578
// > (003A|0214, DS, "0") # 0x2 - Channel Time skew OK
579
// > (003A|021A, US, 0x0010) # 0x2 - Bits per sample OK
580
// > (003A|0220, DS, ".05") # 0x4 - Filter low frequency OK
581
// > (003A|0221, DS, "100") # 0x4 - filter high frequency OK
583
GIL::DICOM::TipoJerarquia* channel_sen_seq = channel_def.buscar_secuencia("003a|0211");
585
if ( channel_src_seq != NULL && channel_src_seq->items.size() > 0 && channel_sen_seq != NULL && channel_sen_seq->items.size() > 0) {
586
GIL::DICOM::TipoJerarquia& channel_src = channel_src_seq->items.front();
587
GIL::DICOM::TipoJerarquia& channel_sen = channel_sen_seq->items.front();
589
ChannelInfo& channelInfo = group.Channels[i];
591
channelInfo.NumSamples = numSamples;
592
channelInfo.SamplingFrecuency = samplingFreq;
594
std::string codingValue = channel_src.getTag("0008|0100");
595
std::string codingSchemeDesignator = channel_src.getTag("0008|0102");
596
channelInfo.SetLead (codingSchemeDesignator, codingValue);
598
channelInfo.SetUnitsValue (channel_sen.getTag ("0008|0100"));
599
channelInfo.SetUnitsMeaning (channel_sen.getTag ("0008|0104"));
601
channelInfo.SetSensitivity (channel_def.getTagAs<double> ("003a|0210", 1.0));
602
channelInfo.SetSensitivityCorrectionFactor (channel_def.getTagAs<double> ("003a|0212", 1.0));
603
channelInfo.SetChannelBaseline (channel_def.getTagAs<double> ("003a|0213", 0.0));
604
channelInfo.SetChannelTimeSkew (channel_def.getTagAs<double> ("003a|0214", 0.0));
605
channelInfo.SetBitsPerSample (channel_def.getTagAs<unsigned int>("003a|021a", 16));
606
channelInfo.SetFilterLowFrequency (channel_def.getTagAs<double> ("003a|0220", 0.0));
607
channelInfo.SetFilterHighFrequency (channel_def.getTagAs<double> ("003a|0221", 0.0));
613
short* data = (short*)tag.GetValor();
614
for (int i = 0; i < numSamples; i++) {
615
for (TListChannelInfo::iterator it = group.Channels.begin(); it != group.Channels.end(); it++) {
616
GNKVisualizator::ChannelInfo& c = *it;
617
c.Samples.push_back(*(data++));
622
GNKVisualizator::ChannelInfo& c = group.Channels.front();
623
for (int i = 0; i < 100; i ++) {
624
c.Samples[i] = (short) 10.0/(c.Multiplier * c.Sensitivity * c.SensitivityCorrectionFactor);
628
}//for secuencias waveforms
631
GIL::DICOM::TipoJerarquia* annotation_seq = base->buscar_secuencia(TAGS::AnnotationSequence);
632
//TODO read referenced channel to read information about each channel
634
if (annotation_seq != NULL) {
635
//for each annotation group one list of strings
636
typedef std::map<int, std::list<std::string> > TMapMultiplexedGroup;
637
typedef std::map<int, TMapMultiplexedGroup> TMapAnnotations;
638
TMapAnnotations annotationsMap;
639
for (GIL::DICOM::TipoJerarquia::ListaJerarquias::reverse_iterator itAnnotations = annotation_seq->items.rbegin(); itAnnotations != annotation_seq->items.rend(); ++itAnnotations)
641
GIL::DICOM::TipoJerarquia& an = (*itAnnotations);
642
std::string textValue = an.getTag(TAGS::UnformattedTextValue);
644
if (textValue != "") {
645
int group = 0, multiplexedGroup = 0;
646
Get(an.getTag(TAGS::AnnotationGroupNumber), group);
647
Get(an.getTag(TAGS::ReferencedChannels), multiplexedGroup);
648
multiplexedGroup -= 1;
649
annotationsMap[multiplexedGroup][group].push_back(textValue);
654
for (TMapAnnotations::iterator itAnnotations = annotationsMap.begin(); itAnnotations != annotationsMap.end(); ++itAnnotations) {
655
for (int i = 0; i < (int)ecgFile->Groups.size(); ++i) {
656
if ((*itAnnotations).second.find(i) != (*itAnnotations).second.end())
658
TMapMultiplexedGroup& annotationsMultiplexed = (*itAnnotations).second;
659
std::ostringstream ostr;
660
for (TMapMultiplexedGroup::iterator itGroups = annotationsMultiplexed.begin(); itGroups != annotationsMultiplexed.end(); ++itGroups) {
661
for (std::list<std::string>::iterator itStrings = (*itGroups).second.begin(); itStrings != (*itGroups).second.end(); ++itStrings) {
662
ostr << (*itStrings) << std::endl;
666
ecgFile->Groups[i].Diagnosis = ostr.str();
670
/////////////////////////////////////////////////////////
671
////////////////GLOBAL MEASUREMENTS//////////////////////
672
/////////////////////////////////////////////////////////
673
std::string s_AvgRRPPItemsCodes[] = {"5.10.2.1-3", "5.10.2.1-5", "5.10.2.5-5", "5.10.2.5-1"};
674
std::string s_AvgRRPPItemsMeaning[] = {_Std("RR Interval"), _Std("PP Interval"), _Std("QTc Interval"), _Std("Vent Rate")};
675
TVectorPairStrings s_AvgRRPPItems;
676
for (int i = 0; i < 4; ++i) {
677
s_AvgRRPPItems.push_back(std::pair<std::string, std::string>(s_AvgRRPPItemsCodes[i], s_AvgRRPPItemsMeaning[i]));
679
std::string s_AvgRRPPUnitsCodes[] = {"ms", "ms", "ms", "/min"};
680
std::string s_AvgRRPPUnitsMeaning[] = {"milliseconds", "milliseconds", "milliseconds", "heartbeat per minute"};
681
TVectorPairStrings s_AvgRRPPUnits;
682
for (int i = 0; i < 4; ++i) {
683
s_AvgRRPPUnits.push_back(std::pair<std::string, std::string>(s_AvgRRPPUnitsCodes[i], s_AvgRRPPUnitsMeaning[i]));
685
std::string s_MeasurementItemsCodes[] = {"5.10.3-1", "5.10.3-2", "5.10.3-3", "5.10.3-4", "5.10.3-5", "5.10.3-11", "5.10.3-13", "5.10.3-15"};
686
std::string s_MeasurementItemsMeaning[] = {"P onset", "P offset", "QRS onset", "QRS offset", "T offset", "P Axis", "QRS Axis", "T Axis"};
687
TVectorPairStrings s_MeasurementItems;
688
for (int i = 0; i < 8; ++i) {
689
s_MeasurementItems.push_back(std::pair<std::string, std::string>(s_MeasurementItemsCodes[i], s_MeasurementItemsMeaning[i]));
691
std::string s_MeasurementUnitsCode[] = {"ms", "ms", "ms", "ms", "ms", "deg", "deg", "deg"};
692
std::string s_MeasurementUnitsValue[]= {"milliseconds", "milliseconds", "milliseconds", "milliseconds", "milliseconds", "degrees", "degrees", "degrees"};
693
TVectorPairStrings s_MeasurementUnits;
694
for (int i = 0; i < 8; ++i) {
695
s_MeasurementUnits.push_back(std::pair<std::string, std::string>(s_MeasurementUnitsCode[i], s_MeasurementUnitsValue[i]));
697
std::string s_MeasurementUnitsPointsCode[] = {"POINT", "POINT", "POINT", "POINT", "POINT", "deg", "deg", "deg"};
698
std::string s_MeasurementUnitsPointsValue[]= {"", "", "", "", "", "degrees", "degrees", "degrees"};
699
TVectorPairStrings s_MeasurementUnitsPoints;
700
for (int i = 0; i < 8; ++i) {
701
s_MeasurementUnitsPoints.push_back(std::pair<std::string, std::string>(s_MeasurementUnitsPointsCode[i], s_MeasurementUnitsPointsValue[i]));
703
std::vector<int> s_MeasurementRWC;
704
s_MeasurementRWC.push_back(1);
705
s_MeasurementRWC.push_back(0);
707
TMapVectorStrings resultAvgRR_PP = GetValues(annotation_seq, s_AvgRRPPItems, s_AvgRRPPUnits, s_MeasurementRWC, false);
708
TMapVectorStrings resultMeasurments = GetValues(annotation_seq, s_MeasurementItems, s_MeasurementUnits, s_MeasurementRWC, true);
712
if (resultAvgRR_PP.size() != 0)
714
TMapVectorStrings temp1 = GetValues(annotation_seq, s_MeasurementItems, s_MeasurementUnitsPoints, s_MeasurementRWC, true);
716
if ((temp1.size() != 0)
717
&& ((resultMeasurments.size() != 0)
718
|| (resultMeasurments.size() < temp1.size())
719
|| (calcNrOfValues(resultMeasurments) < calcNrOfValues(temp1))))
721
if (ecgFile->Groups.size() > 0) {
722
factor = 1000.0f / ecgFile->Groups[0].Channels[0].SamplingFrecuency;
725
resultMeasurments = temp1;
729
if ((resultAvgRR_PP.size() > 0)
730
&& (resultMeasurments.size() > 0))
732
ecgFile->globalMeasurements = GnkPtr<GlobalMeasurements>(new GlobalMeasurements());
733
GNKVisualizator::GlobalMeasurements& mes = (*ecgFile->globalMeasurements);
735
TVectorStrings& resultVector = resultAvgRR_PP.begin()->second;
737
if (resultVector.size() >= 1)
739
if (resultVector[0] != "") {
740
Get(resultVector[0], mes.AvgRR);
743
if (resultVector[1] != "") {
744
Get(resultVector[1], mes.AvgPP);
747
if (resultVector[2] != "") {
749
Get(resultVector[2], qtc);
753
if (resultVector[3] != "") {
754
unsigned short ventRate;
755
Get(resultVector[3], ventRate);
756
mes.setVentRate(ventRate);
760
if ((resultMeasurments.size() > 0)
761
&& ((*resultMeasurments.begin()).second.size()-1 == 8))
763
for (TMapVectorStrings::iterator itMap = resultMeasurments.begin(); itMap != resultMeasurments.end(); ++itMap) {
764
GnkPtr<GNKVisualizator::GlobalMeasurement> measurement(new GNKVisualizator::GlobalMeasurement());
766
TVectorStrings& vectorStrings = (*itMap).second;
767
unsigned short tempUnsignedShort;
770
Get(vectorStrings[0], tempUnsignedShort);
771
measurement->Ponset = (unsigned short)(tempUnsignedShort*factor);
772
Get(vectorStrings[1], tempUnsignedShort);
773
measurement->Poffset = (unsigned short)(tempUnsignedShort*factor);
774
Get(vectorStrings[2], tempUnsignedShort);
775
measurement->QRSonset = (unsigned short)(tempUnsignedShort*factor);
776
Get(vectorStrings[3], tempUnsignedShort);
777
measurement->QRSoffset = (unsigned short)(tempUnsignedShort*factor);
778
Get(vectorStrings[4], tempUnsignedShort);
779
measurement->Toffset = (unsigned short)(tempUnsignedShort*factor);
780
Get(vectorStrings[5], tempShort);
781
measurement->Paxis = tempShort;
782
Get(vectorStrings[6], tempShort);
783
measurement->QRSaxis = tempShort;
784
Get(vectorStrings[7], tempShort);
785
measurement->Taxis = tempShort;
788
mes.measurment.push_back(measurement);
793
}//annotation_seq != NULL
799
bool GNKVisualizator::ECGStudy::CallbackPreCrearDiagnostico(const int indice, GIL::DICOM::TipoJerarquia* pJerarquiaSR, std::list<GnkPtr<GIL::DICOM::TipoPrivateTags> >& /*listaTagsPrivados*/)