1 /*
2 * Gnome Chemisty Utils
3 * spectrumdoc.cc
4 *
5 * Copyright (C) 2007-2011 Jean Bréfort <jean.brefort@normalesup.org>
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License as
9 * published by the Free Software Foundation; either version 3 of the
10 * License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
20 * USA
21 */
22
23 #include "config.h"
24 #include "application.h"
25 #include "spectrumdoc.h"
26 #include "spectrumview.h"
27 #include <gcu/objprops.h>
28 #include <glib/gi18n-lib.h>
29 #include <cstring>
30 #include <sstream>
31 #include <iostream>
32
33 #ifndef HAVE_EXP10
34 # define exp10(x) pow(10.,(x))
35 #endif
36
37 using namespace std;
38
39 namespace gcugtk
40 {
41
SpectrumDocument()42 SpectrumDocument::SpectrumDocument ():
43 gcu::Document (NULL),
44 Printable (),
45 m_XAxisInvertBtn (NULL),
46 m_Empty (true)
47 {
48 m_View = new SpectrumView (this);
49 x = y = NULL;
50 X = Y = R = I = integral = Rt = It = Rp = -1;
51 npoints = 0;
52 maxx = maxy = minx = miny = go_nan;
53 firstx = lastx = deltax = firsty = go_nan;
54 freq = offset = refpoint = go_nan;
55 gtk_page_setup_set_orientation (GetPageSetup (), GTK_PAGE_ORIENTATION_LANDSCAPE);
56 SetScaleType (GCU_PRINT_SCALE_AUTO);
57 SetHorizFit (true);
58 SetVertFit (true);
59 m_IntegralVisible = false;
60 }
61
SpectrumDocument(Application * App,SpectrumView * View)62 SpectrumDocument::SpectrumDocument (Application *App, SpectrumView *View):
63 Document (App),
64 Printable (),
65 m_XAxisInvertBtn (NULL),
66 m_Empty (true)
67 {
68 m_View = (View)? View: new SpectrumView (this);
69 x = y = NULL;
70 X = Xt = Y = R = I = integral = Rt = It = Rp = -1;
71 npoints = 0;
72 maxx = maxy = minx = miny = go_nan;
73 firstx = lastx = deltax = firsty = go_nan;
74 freq = offset = refpoint = go_nan;
75 gtk_page_setup_set_orientation (GetPageSetup (), GTK_PAGE_ORIENTATION_LANDSCAPE);
76 SetScaleType (GCU_PRINT_SCALE_AUTO);
77 SetHorizFit (true);
78 SetVertFit (true);
79 m_IntegralVisible = false;
80 }
81
~SpectrumDocument()82 SpectrumDocument::~SpectrumDocument ()
83 {
84 if (x && X < 0)
85 delete[] x;
86 if (y && Y < 0)
87 delete[] y;
88 for (unsigned i = 0; i < variables.size (); i++)
89 if (variables[i].Values)
90 delete [] variables[i].Values;
91 if (m_View)
92 delete m_View;
93 }
94
Load(char const * uri,char const * mime_type)95 void SpectrumDocument::Load (char const *uri, char const *mime_type)
96 {
97 // Only supporting JCAMP-DX at the moment
98 if (!mime_type || strcmp (mime_type, "chemical/x-jcamp-dx")) {
99 return;
100 }
101 GVfs *vfs = g_vfs_get_default ();
102 GFile *file = g_vfs_get_file_for_uri (vfs, uri);
103 GError *error = NULL;
104 GFileInfo *info = g_file_query_info (file,
105 G_FILE_ATTRIBUTE_STANDARD_SIZE,
106 G_FILE_QUERY_INFO_NONE,
107 NULL, &error);
108 if (error) {
109 g_message ("GIO querry failed: %s", error->message);
110 g_error_free (error);
111 g_object_unref (file);
112 return;
113 }
114 gsize size = g_file_info_get_size (info);
115 g_object_unref (info);
116 GInputStream *input = G_INPUT_STREAM (g_file_read (file, NULL, &error));
117 if (error) {
118 g_message ("GIO could not create the stream: %s", error->message);
119 g_error_free (error);
120 g_object_unref (file);
121 return;
122 }
123 gchar *buf = new gchar[size + 1];
124 gsize n = size;
125 while (n) {
126 n -= g_input_stream_read (input, buf, size, NULL, &error);
127 if (error) {
128 g_message ("GIO could not read the file: %s", error->message);
129 g_error_free (error);
130 delete [] buf;
131 g_object_unref (input);
132 g_object_unref (file);
133 return;
134 }
135 }
136 buf[size] = 0;
137 LoadJcampDx (buf);
138 if (m_App) {
139 char *dirname = g_path_get_dirname (uri);
140 m_App->SetCurDir (dirname);
141 g_free (dirname);
142 }
143 delete [] buf;
144 g_object_unref (file);
145
146 }
147
148 struct data_type_struct {
149 int n; // number of variables
150 bool comma_sep; // whether the separator is a comma
151 bool one_per_line; // whether each line has only one data set
152 bool explicit_indep; // whether the independent variable is explicit
153 char *variables; // each letter is a variable symbol, must be freed
154 };
155
parse_data_type(char const * type,struct data_type_struct & s)156 static void parse_data_type (char const *type, struct data_type_struct &s)
157 {
158 // initialize s
159 s.variables = NULL; // if still NULL when returning, an error occurred
160 s.n = 0;
161 s.one_per_line = false;
162 s.comma_sep = false;
163 s.explicit_indep = true;
164 string variables;
165 if (*type != '(')
166 return;
167 type++;
168 if (*type < 'A' || *type > 'Z')
169 return;
170 variables += *type; //first variable symbol
171 type++;
172 switch (*type) {
173 case ',':
174 s.comma_sep = true;
175 type++;
176 break;
177 case '+':
178 if (type[1] != '+')
179 return;
180 s.explicit_indep = false;
181 type += 2;
182 while (*type == '(' || *type == ')')
183 type++;
184 break;
185 default:
186 break;
187 }
188 // at this point *type should be the second variable symbol
189 if (*type < 'A' || *type > 'Z')
190 return;
191 variables += *type; //second variable symbol
192 type++;
193 // add additional variables if any
194 while (*type == ',' || (*type >= 'A' && *type <= 'Z')) {
195 if (*type != ',')
196 variables += *type;
197 type++;
198 }
199 while (*type == ' ')
200 type++;
201 s.one_per_line = !(*type == '.');
202 s.n = variables.length ();
203 if (s.n > 0)
204 s.variables = g_strdup (variables.c_str ());
205 }
206
207 static struct {char const *name; SpectrumType type;} Types[] = {
208 {"INFRARED SPECTRUM", GCU_SPECTRUM_INFRARED},
209 {"RAMAN SPECTRUM", GCU_SPECTRUM_RAMAN},
210 {"INFRARED PEAK TABLE", GCU_SPECTRUM_INFRARED_PEAK_TABLE},
211 {"INFRARED INTERFEROGRAM", GCU_SPECTRUM_INFRARED_INTERFEROGRAM},
212 {"INFRARED TRANSFORMED SPECTRUM", GCU_SPECTRUM_INFRARED_TRANSFORMED},
213 {"UV-VISIBLE SPECTRUM", GCU_SPECTRUM_UV_VISIBLE},
214 {"NMR SPECTRUM", GCU_SPECTRUM_NMR},
215 {"NMR FID", GCU_SPECTRUM_NMR_FID},
216 {"NMR PEAK TABLE", GCU_SPECTRUM_NMR_PEAK_TABLE},
217 {"NMR PEAK ASSIGNMENTS", GCU_SPECTRUM_NMR_PEAK_ASSIGNMENTS},
218 {"MASS SPECTRUM", GCU_SPECTRUM_MASS},
219 {"UV-VIS SPECTRUM", GCU_SPECTRUM_UV_VISIBLE},
220 {"UV/VISIBLE SPECTRUM", GCU_SPECTRUM_UV_VISIBLE},
221 {"UV/VIS SPECTRUM", GCU_SPECTRUM_UV_VISIBLE}
222 };
223
224 char const *Units[] = {
225 "1/CM",
226 "TRANSMITTANCE",
227 "ABSORBANCE",
228 "PPM",
229 "NANOMETERS",
230 "MICROMETERS",
231 "SECONDS",
232 "HZ",
233 "M/Z",
234 "RELATIVE ABUNDANCE",
235 "RF"
236 };
237
238 static struct {char const *name; SpectrumUnitType unit;} OtherUnits[] = {
239 {"NM", GCU_SPECTRUM_UNIT_NANOMETERS}
240 };
241
242 char const *UnitNames[] = {
243 N_("Wavenumber (cm<sup>−1</sup>)"),
244 N_("Transmittance"),
245 N_("Absorbance"),
246 N_("Chemical shift (ppm)"),
247 N_("Wavelength (nm)"),
248 N_("Wavelength (µm)"),
249 N_("Time (s)"),
250 N_("Frequency (Hz)"),
251 N_("Mass/charge ratio"),
252 N_("Relative abundance"),
253 N_("Response factor")
254 };
255
256 char const *VarTypes[] = {
257 "INDEPENDENT",
258 "DEPENDENT",
259 "PAGE"
260 };
261
262 char const *Formats[] = {
263 "ASDF",
264 "AFFN",
265 "PAC",
266 "SQZ",
267 "DIF"
268 };
269
get_spectrum_data_from_string(char const * type,char const * names[],int max)270 int get_spectrum_data_from_string (char const *type, char const *names[], int max)
271 {
272 int res = 0;
273 char *up = g_ascii_strup (type, -1);
274 while (res < max) {
275 if (!strncmp (up, names[res], strlen (names[res]))) {
276 g_free (up);
277 return res;
278 }
279 res++;
280 }
281 g_free (up);
282 return res;
283 }
284
285 char const *Keys[] = {
286 "TITLE",
287 "JCAMPDX",
288 "DATATYPE",
289 "DATACLASS",
290 "APPLICATION",
291 "DICTIONARY",
292 "BLOCKS",
293 "BLOCKID",
294 "END",
295 "XYDATA",
296 "XYPOINTS",
297 "XYPAIRS",
298 "PEAKTABLE",
299 "PEAKASSIGNMENTS",
300 "RADATA",
301 "XUNITS",
302 "YUNITS",
303 "XLABEL",
304 "YLABEL",
305 "XFACTOR",
306 "YFACTOR",
307 "FIRSTX",
308 "LASTX",
309 "NPOINTS",
310 "FIRSTY",
311 "MAXX",
312 "MINX",
313 "MAXY",
314 "MINY",
315 "RUNITS",
316 "AUNITS",
317 "FIRSTR",
318 "LASTR",
319 "MAXA",
320 "MINA",
321 "RFACTOR",
322 "AFACTOR",
323 "FIRSTA",
324 "ALIAS",
325 "ZPD",
326 "NTUPLES",
327 "VARNAME",
328 "SYMBOL",
329 "VARTYPE",
330 "VARFORM",
331 "VARDIM",
332 "UNITS",
333 "FIRST",
334 "LAST",
335 "MIN",
336 "MAX",
337 "FACTOR",
338 "PAGE",
339 "DATATABLE",
340 "DELTAX",
341 "CLASS",
342 "ORIGIN",
343 "OWNER",
344 "DATE",
345 "TIME",
346 "SOURCEREFERENCE",
347 "CROSSREFERENCE",
348 "SPECTROMETER",
349 "DATASYSTEM",
350 "INSTRUMENTPARAMETERS",
351 "SAMPLEDESCRIPTION",
352 "CASNAME",
353 "NAMES",
354 "MOLEFORM",
355 "CASREGISTRYNO",
356 "WISWESSER",
357 "BEILSTEINLAWSONNO",
358 "MP",
359 "BP",
360 "REFRACTIVEINDEX",
361 "DENSITY",
362 "MW",
363 "CONCENTRATIONS",
364 "SAMPLINGPROCEDURE",
365 "STATE",
366 "PATHLENGTH",
367 "PRESSURE",
368 "TEMPERATURE",
369 "DATAPROCESSING",
370 "SPECTROMETERTYPE",
371 "INLET",
372 "IONIZATIONMODE",
373 "INLETTEMPERATURE",
374 "SOURCETEMPERATURE",
375 "IONIZATIONENERGY",
376 "ACCELERATINGVOLTAGE",
377 "TOTALIONCURRENT",
378 "ACQUISITIONRANGE",
379 "DETECTOR",
380 "SCANNUMBER",
381 "RETENTIONTIME",
382 "BASEPEAK",
383 "BASEPEAKINTENSITY",
384 "RIC",
385 "NOMINALMASS",
386 "MONOISOTOPICMASS",
387 "OBSERVEFREQUENCY",
388 "OBSERVENUCLEUS",
389 "SOLVENTREFERENCE",
390 "DELAY",
391 "ACQUISITIONMODE",
392 "FIELD",
393 "DECOUPLER",
394 "FILTERWIDTH",
395 "ACQUISITIONTIME",
396 "ZEROFILL",
397 "AVERAGES",
398 "DIGITIZERRES",
399 "SPINNINGRATE",
400 "PHASE0",
401 "PHASE1",
402 "MININTENSITY",
403 "MAXINTENSITY",
404 "OBSERVE90",
405 "COUPLINGCONSTANTS",
406 "RELAXATIONTIMES",
407 /* Brücker specific data */
408 "$OFFSET",
409 "$REFERENCEPOINT",
410 NULL
411 };
412
413 enum {
414 JCAMP_INVALID = -10,
415 JCAMP_UNKNOWN,
416 JCAMP_CONTINUE,
417 JCAMP_TITLE = 0,
418 JCAMP_JCAMP_DX,
419 JCAMP_DATA_TYPE,
420 JCAMP_DATACLASS,
421 JCAMP_APPLICATION,
422 JCAMP_DICTIONARY,
423 JCAMP_BLOCKS,
424 JCAMP_BLOCK_ID,
425 JCAMP_END,
426 JCAMP_XYDATA,
427 JCAMP_XYPOINTS,
428 JCAMP_XYPAIRS,
429 JCAMP_PEAK_TABLE,
430 JCAMP_PEAK_ASSIGNMENTS,
431 JCAMP_RADATA,
432 JCAMP_XUNITS,
433 JCAMP_YUNITS,
434 JCAMP_XLABEL,
435 JCAMP_YLABEL,
436 JCAMP_XFACTOR,
437 JCAMP_YFACTOR,
438 JCAMP_FIRSTX,
439 JCAMP_LASTX,
440 JCAMP_NPOINTS,
441 JCAMP_FIRSTY,
442 JCAMP_MAXX,
443 JCAMP_MINX,
444 JCAMP_MAXY,
445 JCAMP_MINY,
446 JCAMP_RUNITS,
447 JCAMP_AUNITS,
448 JCAMP_FIRSTR,
449 JCAMP_LASTR,
450 JCAMP_MAXA,
451 JCAMP_MINA,
452 JCAMP_RFACTOR,
453 JCAMP_AFACTOR,
454 JCAMP_FIRSTA,
455 JCAMP_ALIAS,
456 JCAMP_ZPD,
457 JCAMP_NTUPLES,
458 JCAMP_VAR_NAME,
459 JCAMP_SYMBOL,
460 JCAMP_VAR_TYPE,
461 JCAMP_VAR_FORM,
462 JCAMP_VAR_DIM,
463 JCAMP_UNITS,
464 JCAMP_FIRST,
465 JCAMP_LAST,
466 JCAMP_MIN,
467 JCAMP_MAX,
468 JCAMP_FACTOR,
469 JCAMP_PAGE,
470 JCAMP_DATA_TABLE,
471 JCAMP_DELTAX,
472 JCAMP_CLASS,
473 JCAMP_ORIGIN,
474 JCAMP_OWNER,
475 JCAMP_DATE,
476 JCAMP_TIME,
477 JCAMP_SOURCE_REFERENCE,
478 JCAMP_CROSS_REFERENCE,
479 JCAMP_SPECTROMETER,
480 JCAMP_DATASYSTEM,
481 JCAMP_INSTRUMENT_PARAMETERS,
482 JCAMP_SAMPLE_DESCRIPTION,
483 JCAMP_CAS_NAME,
484 JCAMP_NAMES,
485 JCAMP_MOLEFORM,
486 JCAMP_CAS_REGISTRY_NO,
487 JCAMP_WISWESSER,
488 JCAMP_BEILSTEIN_LAWSON_NO,
489 JCAMP_MP,
490 JCAMP_BP,
491 JCAMP_REFRACTIVE_INDEX,
492 JCAMP_DENSITY,
493 JCAMP_MW,
494 JCAMP_CONCENTRATIONS,
495 JCAMP_SAMPLING_PROCEDURE,
496 JCAMP_STATE,
497 JCAMP_PATH_LENGTH,
498 JCAMP_PRESSURE,
499 JCAMP_TEMPERATURE,
500 JCAMP_DATA_PROCESSING,
501 JCAMP_SPECTROMETER_TYPE,
502 JCAMP_INLET,
503 JCAMP_IONIZATION_MODE,
504 JCAMP_INLET_TEMPERATURE,
505 JCAMP_SOURCE_TEMPERATURE,
506 JCAMP_IONIZATION_ENERGY,
507 JCAMP_ACCELERATING_VOLTAGE,
508 JCAMP_TOTAL_ION_CURRENT,
509 JCAMP_ACQUISITION_RANGE,
510 JCAMP_DETECTOR,
511 JCAMP_SCAN_NUMBER,
512 JCAMP_RETENTION_TIME,
513 JCAMP_BASE_PEAK,
514 JCAMP_BASE_PEAK_INTENSITY,
515 JCAMP_RIC,
516 JCAMP_NOMINAL_MASS,
517 JCAMP_MONOISOTOPIC_MASS,
518 JCAMP_OBSERVE_FREQUENCY,
519 JCAMP_OBSERVE_NUCLEUS,
520 JCAMP_SOLVENT_REFERENCE,
521 JCAMP_DELAY,
522 JCAMP_ACQUISITION_MODE,
523 JCAMP_FIELD,
524 JCAMP_DECOUPLER,
525 JCAMP_FILTER_WIDTH,
526 JCAMP_ACQUISITION_TIME,
527 JCAMP_ZERO_FILL,
528 JCAMP_AVERAGES,
529 JCAMP_DIGITIZER_RES,
530 JCAMP_SPINNING_RATE,
531 JCAMP_PHASE_0,
532 JCAMP_PHASE_1,
533 JCAMP_MIN_INTENSITY,
534 JCAMP_MAX_INTENSITY,
535 JCAMP_OBSERVE_90,
536 JCAMP_COUPLING_CONSTANTS,
537 JCAMP_RELAXATION_TIMES,
538 BRUCKER_OFFSET,
539 VARIAN_OFFSET,
540 JCAMP_MAX_VALID
541 };
542
543 #define KEY_LENGTH 80
544 #define VALUE_LENGTH 128
ReadField(char const * s,char * key,char * buf)545 static int ReadField (char const *s, char *key, char *buf)
546 {
547 char const *data = s, *eq;
548 int i = 0;
549 while (*data != 0 && *data < '#')
550 data++;
551 if (*data == 0)
552 return JCAMP_INVALID;
553 if (!strncmp (data, "$$", 2)) {
554 // This is a comment, just skip
555 return JCAMP_INVALID;
556 }
557 /* if (!strncmp (data, "##$", 3)) {
558 // This is a vendor specific tag, just skip for now
559 return JCAMP_INVALID;
560 }*/
561 if (!strncmp (data, "##", 2)) {
562 // found a field
563 data += 2;
564 eq = strchr (data, '=');
565 i = 0;
566 if (*data == '$' && strncmp (data, "$$", 2)) {
567 key[i++] = '$';
568 data++;
569 }
570 while (data < eq) {
571 if (*data >= 'A' && *data <= 'Z')
572 key[i++] = *data;
573 else if (*data >= 'a' && *data <= 'z')
574 key[i++] = *data - 0x20;
575 data++;
576 }
577 key[i] = 0;
578 if (i == 0)
579 // This is a comment, just skip
580 return JCAMP_INVALID;
581 data = eq + 1;
582 while (*data != 0 && *data < '$')
583 data++;
584 eq = strstr (data, "$$");
585 if (eq && *eq) {
586 strncpy (buf, data, MIN (eq - data, VALUE_LENGTH));
587 buf[MIN (eq - data, VALUE_LENGTH - 1)] = 0;
588 }
589 else {
590 strncpy (buf, data, VALUE_LENGTH);
591 buf[VALUE_LENGTH - 1] = 0;
592 }
593 // strip trailing white spaces:
594 i = strlen (buf) - 1;
595 if (i < 0)
596 return JCAMP_UNKNOWN;
597 while (buf[i] <= ' ' || buf[i] == '"')
598 buf[i--] = 0;
599
600 // Now, get the key value
601 i = JCAMP_TITLE;
602 while (i < JCAMP_MAX_VALID && strcmp (key, Keys[i]))
603 i++;
604 return i;
605 }
606 return JCAMP_UNKNOWN;
607 }
608
on_xunit_changed(GtkComboBox * box,SpectrumDocument * doc)609 static void on_xunit_changed (GtkComboBox *box, SpectrumDocument *doc)
610 {
611 doc->OnXUnitChanged (gtk_combo_box_get_active (box));
612 }
613
on_yunit_changed(GtkComboBox * box,SpectrumDocument * doc)614 static void on_yunit_changed (GtkComboBox *box, SpectrumDocument *doc)
615 {
616 doc->OnYUnitChanged (gtk_combo_box_get_active (box));
617 }
618
on_xaxis_invert(GtkToggleButton * btn,SpectrumDocument * doc)619 static void on_xaxis_invert (GtkToggleButton *btn, SpectrumDocument *doc)
620 {
621 doc->OnXAxisInvert (gtk_toggle_button_get_active (btn));
622 }
623
on_show_integral(GtkButton * btn,SpectrumDocument * doc)624 static void on_show_integral (GtkButton *btn, SpectrumDocument *doc)
625 {
626 gtk_button_set_label (btn, (doc->GetIntegralVisible ()?
627 _("Show integral"): _("Hide integral")));
628 doc->OnShowIntegral ();
629 }
630
631
on_transform_fid(GtkButton * btn,SpectrumDocument * doc)632 static void on_transform_fid (GtkButton *btn, SpectrumDocument *doc)
633 {
634 doc->OnTransformFID (btn);
635 }
636
get_spectrum_type_from_string(char const * buf)637 static SpectrumType get_spectrum_type_from_string (char const *buf)
638 {
639 unsigned i;
640 char *up = g_ascii_strup (buf, -1);
641 for (i = 0; i < G_N_ELEMENTS (Types); i++)
642 if (!strcmp (Types[i].name, up)) {
643 g_free (up);
644 return Types[i].type;
645 }
646 g_free (up);
647 return GCU_SPECTRUM_MAX;
648 }
649
650 #define JCAMP_PREC 1e-2 // fully arbitrary
651
LoadJcampDx(char const * data)652 void SpectrumDocument::LoadJcampDx (char const *data)
653 {
654 char key[KEY_LENGTH];
655 char buf[VALUE_LENGTH];
656 char line[300]; // should be enough
657 int n;
658 deltax = 0.;
659 istringstream s(data);
660 JdxVar var;
661 var.NbValues = 0;
662 var.Symbol = 0;
663 var.Type = GCU_SPECTRUM_TYPE_MAX;
664 var.Unit = GCU_SPECTRUM_UNIT_MAX;
665 var.Format = GCU_SPECTRUM_FORMAT_MAX;
666 var.First = var.Last = var.Min = var.Max = var.Factor = 0.;
667 var.Values = NULL;
668 GString *utf8_str = NULL;
669 while (!s.eof ()) {
670 s.getline (line, 300);
671 parse_line:
672 n = ReadField (line, key, buf);
673 switch (n) {
674 case JCAMP_TITLE:
675 go_guess_encoding (buf, strlen (buf), "ASCII", &utf8_str, NULL);
676 if (utf8_str) {
677 SetTitle (utf8_str->str);
678 g_string_free (utf8_str, TRUE);
679 utf8_str = NULL;
680 } else
681 SetTitle (buf);
682 break;
683 case JCAMP_JCAMP_DX:
684 break;
685 case JCAMP_DATA_TYPE:
686 m_SpectrumType = get_spectrum_type_from_string (buf);
687 break;
688 case JCAMP_DATACLASS:
689 case JCAMP_APPLICATION:
690 case JCAMP_DICTIONARY:
691 case JCAMP_BLOCKS:
692 case JCAMP_BLOCK_ID:
693 break;
694 case JCAMP_END:
695 goto out;
696 case JCAMP_PEAK_TABLE: {
697 // in that case, add drop lines ans remove the normal line
698 GogSeries *series = m_View->GetSeries ();
699 gog_object_add_by_name (GOG_OBJECT (series), "Vertical drop lines", GOG_OBJECT (g_object_new (GOG_TYPE_SERIES_LINES, NULL)));
700 GOStyle *style = go_styled_object_get_style (GO_STYLED_OBJECT (series));
701 style->line.dash_type = GO_LINE_NONE;
702 style->line.auto_dash = false;
703 }
704 case JCAMP_XYPAIRS:
705 case JCAMP_XYDATA:
706 case JCAMP_XYPOINTS: {
707 unsigned read = 0;
708 list<double> l;
709 if (deltax == 0.)
710 deltax = (lastx - firstx) / (npoints - 1);
711 else {
712 if (firstx > lastx && deltax > 0)
713 deltax = -deltax;
714 unsigned n = (unsigned) ((lastx - firstx) / deltax + .1) + 1;
715 if (n && n != npoints) {
716 if (x)
717 delete[] x;
718 x = new double[n];
719 if (y)
720 delete[] y;
721 y = new double[n];
722 }
723 npoints = n;
724 }
725 // FIXME: we should implement a real parser for this value
726 if (!strncmp (buf, "(X++(Y..Y))",strlen ("(X++(Y..Y))")))
727 ReadDataTable (s, x, y);
728 else if (!strncmp (buf, "(XY..XY)",strlen ("(XY..XY)"))) {
729 char *cur;
730 while (1) {
731 if (s.eof ())
732 break; // this should not occur, but a corrupted or bad file is always possible
733 s.getline (line, 300);
734 if (strstr (line, "##")) {
735 if (read > npoints) {
736 g_warning (_("Found too many data!"));
737 // FIXME: throw an exception
738 } else
739 npoints = read;
740 if (!go_finite (minx))
741 go_range_min (x, read, &minx);
742 if (!go_finite (maxx))
743 go_range_max (x, read, &maxx);
744 if (!go_finite (miny))
745 go_range_min (y, read, &miny);
746 if (!go_finite (maxy))
747 go_range_max (y, read, &maxy);
748 goto parse_line;
749 }
750 cur = line;
751 while (*cur) {
752 while (*cur && (*cur < '0' || *cur > '9') && *cur != '-' && *cur !='+')
753 cur++;
754 if (*cur == 0)
755 break;
756 x[read] = g_ascii_strtod (cur, &cur);
757 while (*cur && (*cur < '0' || *cur > '9') && *cur != '-' && *cur !='+')
758 cur++;
759 y[read] = g_ascii_strtod (cur, &cur);
760 read++;
761 }
762 }
763 }
764 break;
765 }
766 case JCAMP_PEAK_ASSIGNMENTS:
767 case JCAMP_RADATA:
768 break;
769 case JCAMP_XUNITS:
770 m_XUnit = (SpectrumUnitType) get_spectrum_data_from_string (buf, Units, GCU_SPECTRUM_UNIT_MAX);
771 if (m_XUnit == GCU_SPECTRUM_UNIT_MAX) {
772 for (unsigned i = 0; i < G_N_ELEMENTS (OtherUnits); i++)
773 if (!strcmp (buf, OtherUnits[i].name)) {
774 m_XUnit = OtherUnits[i].unit;
775 break;
776 }
777 }
778 break;
779 case JCAMP_YUNITS:
780 m_YUnit = (SpectrumUnitType) get_spectrum_data_from_string (buf, Units, GCU_SPECTRUM_UNIT_MAX);
781 if (m_YUnit == GCU_SPECTRUM_UNIT_MAX) {
782 for (unsigned i = 0; i < G_N_ELEMENTS (OtherUnits); i++)
783 if (!strcmp (buf, OtherUnits[i].name)) {
784 m_YUnit = OtherUnits[i].unit;
785 break;
786 }
787 }
788 if (m_YUnit == GCU_SPECTRUM_UNIT_TRANSMITTANCE)
789 m_View->SetAxisBounds (GOG_AXIS_Y, 0., 1., false);
790 break;
791 case JCAMP_XLABEL:
792 case JCAMP_YLABEL:
793 break;
794 case JCAMP_XFACTOR:
795 xfactor = g_ascii_strtod (buf, NULL);
796 break;
797 case JCAMP_YFACTOR:
798 yfactor = g_ascii_strtod (buf, NULL);
799 break;
800 case JCAMP_FIRSTX:
801 firstx = g_ascii_strtod (buf, NULL);
802 break;
803 case JCAMP_LASTX:
804 lastx = g_ascii_strtod (buf, NULL);
805 break;
806 case JCAMP_NPOINTS: {
807 unsigned n = (unsigned) atoi (buf);
808 if (n && n != npoints) {
809 if (x)
810 delete[] x;
811 x = new double[n];
812 if (y)
813 delete[] y;
814 y = new double[n];
815 }
816 npoints = n;
817 break;
818 }
819 case JCAMP_FIRSTY:
820 firsty = g_ascii_strtod (buf, NULL);
821 break;
822 case JCAMP_MAXX:
823 maxx = g_ascii_strtod (buf, NULL);
824 break;
825 case JCAMP_MINX:
826 minx = g_ascii_strtod (buf, NULL);
827 break;
828 case JCAMP_MAXY:
829 maxy = g_ascii_strtod (buf, NULL);
830 break;
831 case JCAMP_MINY:
832 miny = g_ascii_strtod (buf, NULL);
833 break;
834 case JCAMP_RUNITS:
835 case JCAMP_AUNITS:
836 case JCAMP_FIRSTR:
837 case JCAMP_LASTR:
838 case JCAMP_MAXA:
839 case JCAMP_MINA:
840 case JCAMP_RFACTOR:
841 case JCAMP_AFACTOR:
842 case JCAMP_FIRSTA:
843 case JCAMP_ALIAS:
844 case JCAMP_ZPD:
845 case JCAMP_NTUPLES:
846 break;
847 case JCAMP_VAR_NAME: {
848 size_t i = 0;
849 char *cur = buf, *end;
850 while (*cur) {
851 while (*cur && *cur == ' ')
852 cur++;
853 if (!*cur)
854 break;
855 end = strchr (cur, ',');
856 if (end)
857 *end = 0;
858 if (i < variables.size ())
859 variables[i].Name = cur;
860 else {
861 var.Name = cur;
862 variables.push_back (var);
863 var.Name.clear ();
864 }
865 cur = (end)? end + 1: cur + strlen (cur);
866 i++;
867 }
868 break;
869 }
870 case JCAMP_SYMBOL: {
871 size_t i = 0;
872 char *cur = buf, *end;
873 while (*cur) {
874 while (*cur && *cur == ' ')
875 cur++;
876 if (!*cur)
877 break;
878 end = strchr (cur, ',');
879 if (end)
880 *end = 0;
881 if (i < variables.size ())
882 variables[i].Symbol = *cur;
883 else {
884 var.Symbol = *cur;
885 variables.push_back (var);
886 var.Symbol = 0;
887 }
888 switch (*cur) {
889 case 'I':
890 I = i;
891 break;
892 case 'R':
893 R = i;
894 break;
895 case 'X':
896 X = i;
897 break;
898 case 'Y':
899 Y = i;
900 break;
901 default:
902 break;
903 }
904 cur = (end)? end + 1: cur + strlen (cur);
905 i++;
906 }
907 break;
908 }
909 case JCAMP_VAR_TYPE: {
910 size_t i = 0;
911 char *cur = buf, *end;
912 SpectrumVarType Type;
913 while (*cur) {
914 while (*cur && *cur == ' ')
915 cur++;
916 if (!*cur)
917 break;
918 end = strchr (cur, ',');
919 if (end)
920 *end = 0;
921 Type = (SpectrumVarType) get_spectrum_data_from_string (cur, VarTypes, GCU_SPECTRUM_TYPE_MAX);
922 if (i < variables.size ())
923 variables[i].Type = Type;
924 else {
925 var.Type = Type;
926 variables.push_back (var);
927 var.Type = GCU_SPECTRUM_TYPE_MAX;
928 }
929 cur = (end)? end + 1: cur + strlen (cur);
930 i++;
931 }
932 break;
933 break;
934 }
935 case JCAMP_VAR_FORM: {
936 size_t i = 0;
937 char *cur = buf, *end;
938 SpectrumFormatType Format;
939 while (*cur) {
940 while (*cur && *cur == ' ')
941 cur++;
942 if (!*cur)
943 break;
944 end = strchr (cur, ',');
945 if (end)
946 *end = 0;
947 Format = (SpectrumFormatType) get_spectrum_data_from_string (cur, Formats, GCU_SPECTRUM_FORMAT_MAX);
948 if (i < variables.size ())
949 variables[i].Format = Format;
950 else {
951 var.Format = Format;
952 variables.push_back (var);
953 var.Format = GCU_SPECTRUM_FORMAT_MAX;
954 }
955 cur = (end)? end + 1: cur + strlen (cur);
956 i++;
957 }
958 break;
959 }
960 case JCAMP_VAR_DIM: {
961 size_t i = 0;
962 char *cur = buf;
963 unsigned dim;
964 while (*cur) {
965 dim = strtoul (cur, &cur, 10);
966 if (*cur)
967 cur++;
968 if (i < variables.size ())
969 variables[i].NbValues = dim;
970 else {
971 var.NbValues = dim;
972 variables.push_back (var);
973 var.NbValues = 0;
974 }
975 i++;
976 }
977 break;
978 }
979 case JCAMP_UNITS: {
980 size_t i = 0;
981 char *cur = buf, *end;
982 SpectrumUnitType Unit;
983 while (*cur) {
984 while (*cur && *cur == ' ')
985 cur++;
986 if (!*cur)
987 break;
988 end = strchr (cur, ',');
989 if (end)
990 *end = 0;
991 Unit = (SpectrumUnitType) get_spectrum_data_from_string (cur, Units, GCU_SPECTRUM_UNIT_MAX);
992 if (i < variables.size ())
993 variables[i].Unit = Unit;
994 else {
995 var.Unit = Unit;
996 variables.push_back (var);
997 var.Unit = GCU_SPECTRUM_UNIT_MAX;
998 }
999 cur = (end)? end + 1: cur + strlen (cur);
1000 i++;
1001 }
1002 break;
1003 }
1004 case JCAMP_FIRST: {
1005 size_t i = 0;
1006 char *cur = buf;
1007 double x;
1008 while (*cur) {
1009 x = g_ascii_strtod (cur, &cur);
1010 if (*cur)
1011 cur++;
1012 if (i < variables.size ())
1013 variables[i].First = x;
1014 else {
1015 var.First = x;
1016 variables.push_back (var);
1017 var.First = 0.;
1018 }
1019 i++;
1020 }
1021 break;
1022 }
1023 case JCAMP_LAST: {
1024 size_t i = 0;
1025 char *cur = buf;
1026 double x;
1027 while (*cur) {
1028 x = g_ascii_strtod (cur, &cur);
1029 if (*cur)
1030 cur++;
1031 if (i < variables.size ())
1032 variables[i].Last = x;
1033 else {
1034 var.Last = x;
1035 variables.push_back (var);
1036 var.Last = 0.;
1037 }
1038 i++;
1039 }
1040 break;
1041 }
1042 case JCAMP_MIN: {
1043 size_t i = 0;
1044 char *cur = buf;
1045 double x;
1046 while (*cur) {
1047 x = g_ascii_strtod (cur, &cur);
1048 if (*cur)
1049 cur++;
1050 if (i < variables.size ())
1051 variables[i].Min = x;
1052 else {
1053 var.Min = x;
1054 variables.push_back (var);
1055 var.Min = 0.;
1056 }
1057 i++;
1058 }
1059 break;
1060 }
1061 case JCAMP_MAX: {
1062 size_t i = 0;
1063 char *cur = buf;
1064 double x;
1065 while (*cur) {
1066 x = g_ascii_strtod (cur, &cur);
1067 if (*cur)
1068 cur++;
1069 if (i < variables.size ())
1070 variables[i].Max = x;
1071 else {
1072 var.Max = x;
1073 variables.push_back (var);
1074 var.Max = 0.;
1075 }
1076 i++;
1077 }
1078 break;
1079 }
1080 case JCAMP_FACTOR: {
1081 size_t i = 0;
1082 char *cur = buf;
1083 double x;
1084 while (*cur) {
1085 x = g_ascii_strtod (cur, &cur);
1086 if (*cur)
1087 cur++;
1088 if (i < variables.size ())
1089 variables[i].Factor = x;
1090 else {
1091 var.Factor = x;
1092 variables.push_back (var);
1093 var.Factor = 0.;
1094 }
1095 i++;
1096 }
1097 break;
1098 }
1099 case JCAMP_PAGE: {
1100 unsigned num = atoi (strchr (buf, '=') + 1);
1101 if (num == 1) {
1102 unsigned max = 0;
1103 for (unsigned i = 0; i < variables.size (); i++) {
1104 JdxVar &v = variables[i];
1105 if (v.Name == "PAGE NUMBER")
1106 continue;
1107 if (v.NbValues > max)
1108 max = v.NbValues;
1109 switch (v.Type) {
1110 case GCU_SPECTRUM_TYPE_INDEPENDENT:
1111 if (v.Symbol == 'X') {
1112 firstx = v.First;
1113 lastx = v.Last;
1114 minx = v.Min;
1115 maxx = v.Max;
1116 xfactor = v.Factor;
1117 deltax = (lastx - firstx) / (v.NbValues - 1);
1118 }
1119 break;
1120 case GCU_SPECTRUM_TYPE_DEPENDENT:
1121 break;
1122 default:
1123 break;
1124 }
1125 }
1126 npoints = max;
1127 }
1128 break;
1129 }
1130 case JCAMP_DATA_TABLE: {
1131 // first split fields, we might have two, but the second is optional
1132 char *vlist = buf, *desc;
1133 while (*vlist && *vlist == ' ')
1134 vlist++;
1135 if (!*vlist)
1136 break;
1137 desc = strchr (vlist, ',');
1138 if (desc)
1139 *desc = 0;
1140 desc++;
1141 while (*desc && *desc == ' ')
1142 desc++;
1143 struct data_type_struct dts;
1144 parse_data_type (vlist, dts);
1145 if (!strncmp (desc, "XYDATA", 6)) {
1146 if (dts.n == 2 && !dts.one_per_line && !dts.explicit_indep) {
1147 int first = -1, second = -1;
1148 switch (*dts.variables) {
1149 case 'I':
1150 first = I;
1151 break;
1152 case 'R':
1153 first = R;
1154 break;
1155 case 'X':
1156 first = X;
1157 break;
1158 case 'Y':
1159 first = Y;
1160 break;
1161 }
1162 switch (dts.variables[1]) {
1163 case 'I':
1164 second = I;
1165 break;
1166 case 'R':
1167 second = R;
1168 break;
1169 case 'X':
1170 second = X;
1171 break;
1172 case 'Y':
1173 second = Y;
1174 break;
1175 }
1176 if (first >=0 && second >=0 && first != second) {
1177 if (variables[first].Values)
1178 delete [] variables[first].Values;
1179 variables[first].Values = new double[variables[first].NbValues];
1180 if (variables[second].Values)
1181 delete [] variables[second].Values;
1182 variables[second].Values = new double[variables[second].NbValues];
1183 yfactor = variables[second].Factor;
1184 firsty = variables[second].First;
1185 ReadDataTable (s, variables[first].Values, variables[second].Values);
1186 }
1187 }
1188 } //what should be done for PROFILE, PEAKS and COUTOUR?
1189 g_free (dts.variables);
1190 break;
1191 }
1192 case JCAMP_DELTAX:
1193 deltax = g_ascii_strtod (buf, NULL);
1194 break;
1195 case JCAMP_CLASS:
1196 case JCAMP_ORIGIN:
1197 case JCAMP_OWNER:
1198 case JCAMP_DATE:
1199 case JCAMP_TIME:
1200 case JCAMP_SOURCE_REFERENCE:
1201 case JCAMP_CROSS_REFERENCE:
1202 case JCAMP_SPECTROMETER:
1203 case JCAMP_DATASYSTEM:
1204 case JCAMP_INSTRUMENT_PARAMETERS:
1205 case JCAMP_SAMPLE_DESCRIPTION:
1206 case JCAMP_CAS_NAME:
1207 case JCAMP_NAMES:
1208 case JCAMP_MOLEFORM:
1209 case JCAMP_CAS_REGISTRY_NO:
1210 case JCAMP_WISWESSER:
1211 case JCAMP_BEILSTEIN_LAWSON_NO:
1212 case JCAMP_MP:
1213 case JCAMP_BP:
1214 case JCAMP_REFRACTIVE_INDEX:
1215 case JCAMP_DENSITY:
1216 case JCAMP_MW:
1217 case JCAMP_CONCENTRATIONS:
1218 case JCAMP_SAMPLING_PROCEDURE:
1219 case JCAMP_STATE:
1220 case JCAMP_PATH_LENGTH:
1221 case JCAMP_PRESSURE:
1222 case JCAMP_TEMPERATURE:
1223 case JCAMP_DATA_PROCESSING:
1224 case JCAMP_SPECTROMETER_TYPE:
1225 case JCAMP_INLET:
1226 case JCAMP_IONIZATION_MODE:
1227 case JCAMP_INLET_TEMPERATURE:
1228 case JCAMP_SOURCE_TEMPERATURE:
1229 case JCAMP_IONIZATION_ENERGY:
1230 case JCAMP_ACCELERATING_VOLTAGE:
1231 case JCAMP_TOTAL_ION_CURRENT:
1232 case JCAMP_ACQUISITION_RANGE:
1233 case JCAMP_DETECTOR:
1234 case JCAMP_SCAN_NUMBER:
1235 case JCAMP_RETENTION_TIME:
1236 case JCAMP_BASE_PEAK:
1237 case JCAMP_BASE_PEAK_INTENSITY:
1238 case JCAMP_RIC:
1239 case JCAMP_NOMINAL_MASS:
1240 case JCAMP_MONOISOTOPIC_MASS:
1241 break;
1242 case JCAMP_OBSERVE_FREQUENCY:
1243 freq = g_ascii_strtod (buf, NULL);
1244 break;
1245 case JCAMP_OBSERVE_NUCLEUS:
1246 case JCAMP_SOLVENT_REFERENCE:
1247 case JCAMP_DELAY:
1248 case JCAMP_ACQUISITION_MODE:
1249 case JCAMP_FIELD:
1250 case JCAMP_DECOUPLER:
1251 case JCAMP_FILTER_WIDTH:
1252 case JCAMP_ACQUISITION_TIME:
1253 case JCAMP_ZERO_FILL:
1254 case JCAMP_AVERAGES:
1255 case JCAMP_DIGITIZER_RES:
1256 case JCAMP_SPINNING_RATE:
1257 case JCAMP_PHASE_0:
1258 case JCAMP_PHASE_1:
1259 case JCAMP_MIN_INTENSITY:
1260 case JCAMP_MAX_INTENSITY:
1261 case JCAMP_OBSERVE_90:
1262 case JCAMP_COUPLING_CONSTANTS:
1263 case JCAMP_RELAXATION_TIMES:
1264 break;
1265 case BRUCKER_OFFSET:
1266 offset = g_ascii_strtod (buf, NULL);
1267 break;
1268 case VARIAN_OFFSET:
1269 refpoint = g_ascii_strtod (buf, NULL);
1270 break;
1271 default:
1272 break;
1273 }
1274 }
1275
1276 out:
1277 Loaded ();
1278 }
1279
ReadDataLine(char const * data,list<double> & l)1280 void SpectrumDocument::ReadDataLine (char const *data, list<double> &l)
1281 {
1282 int i = 1, j;
1283 char buf[32], c = data[0];
1284 double val = 0., newval = 0.;
1285 bool pos, diff = false;
1286 char *eq = strstr (const_cast <char *> (data), "$$");
1287 if (eq)
1288 *eq = 0;
1289 pos = true;
1290 while (c) {
1291 switch (c) {
1292 case ' ':
1293 c = data[i++];
1294 continue;
1295 case '-':
1296 pos = false;
1297 case '+':
1298 c = data[i++];
1299 if ((c < '0' || c > '9') && c != '.') // FIXME: throw an exception
1300 {;}
1301 continue;
1302 case '.':
1303 case '0':
1304 case '1':
1305 case '2':
1306 case '3':
1307 case '4':
1308 case '5':
1309 case '6':
1310 case '7':
1311 case '8':
1312 case '9':
1313 buf[0] = c;
1314 diff = false;
1315 break;
1316 case '@':
1317 case 'A':
1318 case 'B':
1319 case 'C':
1320 case 'D':
1321 case 'E':
1322 case 'F':
1323 case 'G':
1324 case 'H':
1325 case 'I':
1326 buf[0] = c - 0x10;
1327 diff = false;
1328 break;
1329 case 'a':
1330 case 'b':
1331 case 'c':
1332 case 'd':
1333 case 'e':
1334 case 'f':
1335 case 'g':
1336 case 'h':
1337 case 'i':
1338 pos = false;
1339 diff = false;
1340 buf[0] = c - 0x30;
1341 break;
1342 case '%':
1343 c = 'I';
1344 case 'J':
1345 case 'K':
1346 case 'L':
1347 case 'M':
1348 case 'N':
1349 case 'O':
1350 case 'P':
1351 case 'Q':
1352 case 'R':
1353 diff = true;
1354 buf[0] = c - 0x19;
1355 break;
1356 case 'j':
1357 case 'k':
1358 case 'l':
1359 case 'm':
1360 case 'n':
1361 case 'o':
1362 case 'p':
1363 case 'q':
1364 case 'r':
1365 pos = false;
1366 diff = true;
1367 buf[0] = c - 0x39;
1368 break;
1369 case 's':
1370 c = '[';
1371 case 'S':
1372 case 'T':
1373 case 'U':
1374 case 'V':
1375 case 'W':
1376 case 'X':
1377 case 'Y':
1378 case 'Z': {
1379 buf[0] = c - 0x22;
1380 j = 1;
1381 while (c = data[i++], (c >= '0' && c <= '9')) {
1382 if (j == 31) {
1383 g_warning (_("Constant too long"));
1384 break;
1385 }
1386 buf[j++] = c;
1387 }
1388 buf[j] = 0;
1389 int m, n = atoi (buf);
1390 for (m = 1; m < n; m++) {
1391 if (diff)
1392 val += newval;
1393 l.push_back (val);
1394 }
1395 continue;
1396 }
1397 case '?':
1398 diff = false;
1399 val = go_nan;
1400 newval = 0.;
1401 l.push_back (go_nan);
1402 c = data[i++];
1403 continue;
1404 default:
1405 if (c > ' ')
1406 g_warning (_("Invalid character in data block"));
1407 c = data[i++];
1408 continue;
1409 }
1410 j = 1;
1411 while (c = data[i++], (c >= '0' && c <= '9') || c == '.') {
1412 if (j == 31) {
1413 g_warning (_("Constant too long"));
1414 break;
1415 }
1416 buf[j++] = c;
1417 }
1418 buf[j] = 0;
1419 newval = g_ascii_strtod (buf, NULL);
1420 if (!pos)
1421 newval = - newval;
1422 if (diff)
1423 val += newval;
1424 else
1425 val = newval;
1426 l.push_back (val);
1427 pos = true;
1428 }
1429 }
1430
DoPrint(G_GNUC_UNUSED GtkPrintOperation * print,GtkPrintContext * context,G_GNUC_UNUSED int page) const1431 void SpectrumDocument::DoPrint (G_GNUC_UNUSED GtkPrintOperation *print, GtkPrintContext *context, G_GNUC_UNUSED int page) const
1432 {
1433 cairo_t *cr;
1434 gdouble width, height;
1435
1436 cr = gtk_print_context_get_cairo_context (context);
1437 width = gtk_print_context_get_width (context);
1438 height = gtk_print_context_get_height (context);
1439 int w, h; // size in points
1440 w = m_View->GetWidth ();
1441 h = m_View->GetHeight ();
1442 switch (GetScaleType ()) {
1443 case GCU_PRINT_SCALE_NONE:
1444 break;
1445 case GCU_PRINT_SCALE_FIXED:
1446 w *= Printable::GetScale ();
1447 h *= Printable::GetScale ();
1448 break;
1449 case GCU_PRINT_SCALE_AUTO:
1450 if (GetHorizFit ())
1451 w = width;
1452 if (GetVertFit ())
1453 h = height;
1454 break;
1455 }
1456 double x = 0., y = 0.;
1457 if (GetHorizCentered ())
1458 x = (width - w) / 2.;
1459 if (GetVertCentered ())
1460 y = (height - h) / 2.;
1461 cairo_save (cr);
1462 cairo_translate (cr, x, y);
1463 m_View->Render (cr, w, h);
1464 cairo_restore (cr);
1465 }
1466
GetGtkWindow()1467 GtkWindow *SpectrumDocument::GetGtkWindow ()
1468 {
1469 GtkWidget *w = m_View->GetWidget ();
1470 return (GtkWindow*) ((w)? gtk_widget_get_toplevel (m_View->GetWidget ()): NULL);
1471 }
1472
ReadDataTable(istream & s,double * x,double * y)1473 void SpectrumDocument::ReadDataTable (istream &s, double *x, double *y)
1474 {
1475 char line[300]; // should be enough
1476 unsigned read = 0;
1477 list<double> l;
1478 int previous = 0;
1479 double previousx = firstx;
1480 while (1) {
1481 if (s.eof ())
1482 break; // this should not occur, but a corrupted or bad file is always possible
1483 s.getline (line, 300);
1484 if (strstr (line, "##")) {
1485 s.seekg (-strlen (line) -1, s.cur);
1486 if (read > npoints) {
1487 g_warning (_("Found too many data!"));
1488 // FIXME: throw an exception
1489 } else
1490 npoints = read;
1491 break;
1492 }
1493 ReadDataLine (line, l);
1494 if (l.empty ())
1495 continue;
1496 list<double>::iterator i = l.begin (), end = l.end ();
1497 if (read > 0) {
1498 double x1 = (*i) * xfactor;
1499 int n = read - previous - (int)round((x1-previousx)/deltax);
1500 previous = read;
1501 previousx = x1;
1502 if (n == 0) {
1503 // values are the same, no y reminder, and nothing to do
1504 } else if (n == 1) {
1505 i++;
1506 previous--;
1507 double y0 = (*i) * yfactor;
1508 if (fabs (y0 - y[read - 1]) > fmax (fabs (y0), fabs (y[read - 1])) * JCAMP_PREC)
1509 g_warning (_("Data check failed!"));
1510 } else if (previousx - x1 < 0.) {
1511 unsigned missing = (unsigned) round ((x1 - previousx) / deltax), n;
1512 for (n = 0; n < missing; n++) {
1513 if (read > npoints) // FIXME: Throw an exception
1514 break;
1515 x[read] = firstx + deltax * read;
1516 y[read++] = go_nan;
1517 }
1518 } else {
1519 // FIXME: duplicate values, throw an exception
1520 }
1521 } else {
1522 x[read] = (*i) * xfactor;
1523 if (fabs (x[0] - firstx) > fabs (deltax * JCAMP_PREC)) {
1524 xfactor = firstx / (*i);
1525 deltax = (lastx - firstx) / (npoints - 1);
1526 g_warning (_("Data check failed: FIRSTX!"));
1527 }
1528 i++;
1529 y[read++] = (*i) * yfactor;
1530 if (fabs (firsty - y[0]) > fmax (fabs (firsty), fabs (y[0])) * JCAMP_PREC)
1531 g_warning (_("Data check failed: FIRSTY!"));
1532 }
1533 for (i++; i != end; i++) {
1534 if (read >= npoints) { // FIXME: Throw an exception
1535 g_warning (_("Found too many data"));
1536 break;
1537 }
1538 x[read] = firstx + deltax * read;
1539 y[read++] = (*i) * yfactor;
1540 }
1541 l.clear ();
1542 }
1543 if (!go_finite (minx))
1544 go_range_min (x, read, &minx);
1545 if (!go_finite (maxx))
1546 go_range_max (x, read, &maxx);
1547 if (!go_finite (miny))
1548 go_range_min (y, read, &miny);
1549 if (!go_finite (maxy))
1550 go_range_max (y, read, &maxy);
1551 while (npoints > read) {
1552 // this should never occur, fill missing y values with nan
1553 x[read] = minx + deltax * read;
1554 y[read++] = go_nan;
1555 }
1556 if (isnan (maxx)) {
1557 maxx = MAX (firstx, lastx);
1558 minx = MIN (firstx, lastx);
1559 }
1560 }
1561
OnXUnitChanged(int i)1562 void SpectrumDocument::OnXUnitChanged (int i)
1563 {
1564 SpectrumUnitType unit = GCU_SPECTRUM_UNIT_MAX;
1565 bool invert_axis = false;
1566 switch (m_SpectrumType) {
1567 case GCU_SPECTRUM_NMR:
1568 unit = (i == 0)? GCU_SPECTRUM_UNIT_PPM: GCU_SPECTRUM_UNIT_HZ;
1569 invert_axis = true;
1570 break;
1571 case GCU_SPECTRUM_INFRARED:
1572 case GCU_SPECTRUM_RAMAN:
1573 if (i == 1) {
1574 unit = GCU_SPECTRUM_UNIT_CM_1;
1575 invert_axis = true;
1576 } else
1577 unit = GCU_SPECTRUM_UNIT_MICROMETERS;
1578 break;
1579 case GCU_SPECTRUM_UV_VISIBLE:
1580 if (i == 1) {
1581 unit = GCU_SPECTRUM_UNIT_CM_1;
1582 invert_axis = true;
1583 } else
1584 unit = GCU_SPECTRUM_UNIT_NANOMETERS;
1585 break;
1586 default:
1587 break;
1588 }
1589 if (unit == GCU_SPECTRUM_UNIT_MAX)
1590 return;
1591 GOData *godata;
1592 GogSeries *series = m_View->GetSeries ();
1593 if (x && m_XUnit == unit) {
1594 X = -1;
1595 godata = go_data_vector_val_new (x, npoints, NULL);
1596 gog_series_set_dim (series, 0, godata, NULL);
1597 m_View->SetAxisBounds (GOG_AXIS_X, minx, maxx, invert_axis);
1598 m_View->SetAxisLabel (GOG_AXIS_X, _(UnitNames[m_XUnit]));
1599 if (m_XAxisInvertBtn) {
1600 g_signal_handler_block (m_XAxisInvertBtn, m_XAxisInvertSgn);
1601 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (m_XAxisInvertBtn), invert_axis);
1602 g_signal_handler_unblock (m_XAxisInvertBtn, m_XAxisInvertSgn);
1603 }
1604 } else {
1605 unsigned i, j;
1606 double (*conv) (double, double, double);
1607 double f, o;
1608 for (i = 0; i < variables.size (); i++)
1609 if (variables[i].Symbol == 'X' && variables[i].Unit == unit)
1610 break;
1611 if (i == variables.size ()) {
1612 // Add new data vector
1613 JdxVar v;
1614 if (X >=0) {
1615 conv = GetConversionFunction (variables[X].Unit, unit, f, o);
1616 if (!conv)
1617 return;
1618 v.Name = _(UnitNames[variables[X].Unit]);
1619 v.Symbol = variables[X].Symbol;
1620 v.Type = variables[X].Type;
1621 v.Unit = unit;
1622 v.Format = variables[X].Format;
1623 v.NbValues = variables[X].NbValues;
1624 v.First = conv (variables[X].First, f, o);
1625 v.Last = conv (variables[X].Last, f, o);
1626 v.Min = conv (variables[X].Min, f, o);
1627 v.Max = conv (variables[X].Max, f, o);
1628 v.Factor = 1.;
1629 v.Values = new double[variables[X].NbValues];
1630 for (j = 0; j < variables[X].NbValues; j++)
1631 v.Values[j] = conv (variables[X].Values[j], f, o);
1632 } else {
1633 conv = GetConversionFunction (m_XUnit, unit, f, o);
1634 if (!conv)
1635 return;
1636 v.Name = _(UnitNames[unit]);
1637 v.Symbol = 'X';
1638 v.Type = GCU_SPECTRUM_TYPE_DEPENDENT;
1639 v.Unit = unit;
1640 v.Format = GCU_SPECTRUM_FORMAT_MAX;
1641 v.NbValues = npoints;
1642 v.First = conv (firstx, f, o);
1643 v.Last = conv (lastx, f, o);
1644 v.Min = conv (minx, f, o);
1645 v.Max = conv (maxx, f, o);
1646 v.Factor = 1.;
1647 v.Values = new double[npoints];
1648 for (j = 0; j < npoints; j++)
1649 v.Values[j] = conv (x[j], f, o);
1650 }
1651 if (v.Min > v.Max) {
1652 f = v.Min;
1653 v.Min = v.Max;
1654 v.Max = f;
1655 }
1656 variables.push_back (v);
1657 }
1658 X = i;
1659 godata = go_data_vector_val_new (variables[i].Values, variables[i].NbValues, NULL);
1660 gog_series_set_dim (series, 0, godata, NULL);
1661 m_View->SetAxisBounds (GOG_AXIS_X, variables[i].Min, variables[i].Max, invert_axis);
1662 m_View->SetAxisLabel (GOG_AXIS_X, _(UnitNames[variables[i].Unit]));
1663 if (m_XAxisInvertBtn) {
1664 g_signal_handler_block (m_XAxisInvertBtn, m_XAxisInvertSgn);
1665 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (m_XAxisInvertBtn), invert_axis);
1666 g_signal_handler_unblock (m_XAxisInvertBtn, m_XAxisInvertSgn);
1667 }
1668 if (integral > 0) {
1669 g_object_ref (godata);
1670 }
1671 }
1672 if (integral > 0) {
1673 g_object_ref (godata);
1674 gog_series_set_dim (variables[integral].Series, 0, godata, NULL);
1675 }
1676 }
1677
OnYUnitChanged(int i)1678 void SpectrumDocument::OnYUnitChanged (int i)
1679 {
1680 SpectrumUnitType unit = GCU_SPECTRUM_UNIT_MAX;
1681 bool invert_axis = false;
1682 switch (m_SpectrumType) {
1683 case GCU_SPECTRUM_INFRARED:
1684 case GCU_SPECTRUM_RAMAN:
1685 case GCU_SPECTRUM_UV_VISIBLE:
1686 unit = (i == 0)? GCU_SPECTRUM_UNIT_ABSORBANCE: GCU_SPECTRUM_UNIT_TRANSMITTANCE;
1687 break;
1688 default:
1689 break;
1690 }
1691 if (unit == GCU_SPECTRUM_UNIT_MAX)
1692 return;
1693 GOData *godata;
1694 GogSeries *series = m_View->GetSeries ();
1695 if (m_YUnit == unit) {
1696 Y = -1;
1697 godata = go_data_vector_val_new (y, npoints, NULL);
1698 gog_series_set_dim (series, 1, godata, NULL);
1699 m_View->SetAxisBounds (GOG_AXIS_Y, miny, maxy, invert_axis);
1700 m_View->SetAxisLabel (GOG_AXIS_Y, _(UnitNames[m_YUnit]));
1701 } else {
1702 unsigned i, j;
1703 double (*conv) (double, double, double);
1704 double f, o;
1705 for (i = 0; i < variables.size (); i++)
1706 if (variables[i].Symbol == 'Y' && variables[i].Unit == unit)
1707 break;
1708 if (i == variables.size ()) {
1709 // Add new data vector
1710 JdxVar v;
1711 if (Y >=0) {
1712 conv = GetConversionFunction (variables[Y].Unit, unit, f, o);
1713 if (!conv)
1714 return;
1715 v.Name = _(UnitNames[variables[Y].Unit]);
1716 v.Symbol = variables[Y].Symbol;
1717 v.Type = variables[Y].Type;
1718 v.Unit = unit;
1719 v.Format = variables[Y].Format;
1720 v.NbValues = variables[Y].NbValues;
1721 v.First = conv (variables[Y].First, f, o);
1722 v.Last = conv (variables[Y].Last, f, o);
1723 v.Min = conv (variables[Y].Min, f, o);
1724 v.Max = conv (variables[Y].Max, f, o);
1725 v.Factor = 1.;
1726 v.Values = new double[variables[Y].NbValues];
1727 for (j = 0; j < variables[Y].NbValues; j++)
1728 v.Values[j] = conv (variables[Y].Values[j], f, o);
1729 } else {
1730 conv = GetConversionFunction (m_YUnit, unit, f, o);
1731 if (!conv)
1732 return;
1733 v.Name = _(UnitNames[unit]);
1734 v.Symbol = 'Y';
1735 v.Type = GCU_SPECTRUM_TYPE_DEPENDENT;
1736 v.Unit = unit;
1737 v.Format = GCU_SPECTRUM_FORMAT_MAX;
1738 v.NbValues = npoints;
1739 v.First = conv (firsty, f, o);
1740 v.Last = 0.; // not important
1741 v.Min = conv (miny, f, o);
1742 v.Max = conv (maxy, f, o);
1743 v.Factor = 1.;
1744 v.Values = new double[npoints];
1745 for (j = 0; j < npoints; j++)
1746 v.Values[j] = conv (y[j], f, o);
1747 }
1748 if (v.Min > v.Max) {
1749 f = v.Min;
1750 v.Min = v.Max;
1751 v.Max = f;
1752 }
1753 variables.push_back (v);
1754 }
1755 Y = i;
1756 godata = go_data_vector_val_new (variables[i].Values, variables[i].NbValues, NULL);
1757 gog_series_set_dim (series, 1, godata, NULL);
1758 m_View->SetAxisBounds (GOG_AXIS_Y, variables[i].Min, variables[i].Max, invert_axis);
1759 m_View->SetAxisLabel (GOG_AXIS_Y, _(UnitNames[variables[i].Unit]));
1760 }
1761 }
1762
mult(double val,double f,double offset)1763 static double mult (double val, double f, double offset)
1764 {
1765 return val * f + offset;
1766 }
1767
inv(double val,double f,double offset)1768 static double inv (double val, double f, double offset)
1769 {
1770 return f / val + offset;
1771 }
1772
logm(double val,double f,double offset)1773 static double logm (double val, double f, double offset)
1774 {
1775 return -log10 (val * f + offset);
1776 }
1777
expm(double val,double f,double offset)1778 static double expm (double val, double f, double offset)
1779 {
1780 return exp10 (-val) * f + offset;
1781 }
1782
GetConversionFunction(SpectrumUnitType oldu,SpectrumUnitType newu,double & factor,double & shift)1783 double (*SpectrumDocument::GetConversionFunction (SpectrumUnitType oldu, SpectrumUnitType newu, double &factor, double &shift)) (double, double, double)
1784 {
1785 switch (oldu) {
1786 case GCU_SPECTRUM_UNIT_CM_1:
1787 if (newu == GCU_SPECTRUM_UNIT_NANOMETERS) {
1788 factor = 1.e7;
1789 shift = 0;
1790 return inv;
1791 }
1792 if (newu == GCU_SPECTRUM_UNIT_MICROMETERS) {
1793 factor = 1.e4;
1794 shift = 0;
1795 return inv;
1796 }
1797 break;
1798 case GCU_SPECTRUM_UNIT_TRANSMITTANCE:
1799 if (newu == GCU_SPECTRUM_UNIT_ABSORBANCE) {
1800 factor = 1.;
1801 shift = 0.;
1802 return logm;
1803 }
1804 break;
1805 case GCU_SPECTRUM_UNIT_ABSORBANCE:
1806 if (newu == GCU_SPECTRUM_UNIT_TRANSMITTANCE) {
1807 factor = 1.;
1808 shift = 0.;
1809 return expm;
1810 }
1811 break;
1812 case GCU_SPECTRUM_UNIT_PPM:
1813 if (go_finite (freq) && newu == GCU_SPECTRUM_UNIT_HZ) {
1814 factor = freq;
1815 shift = 0;
1816 return mult;
1817 }
1818 break;
1819 case GCU_SPECTRUM_UNIT_NANOMETERS:
1820 if (newu == GCU_SPECTRUM_UNIT_CM_1) {
1821 factor = 1.e7;
1822 shift = 0;
1823 return inv;
1824 }
1825 break;
1826 case GCU_SPECTRUM_UNIT_MICROMETERS:
1827 if (newu == GCU_SPECTRUM_UNIT_CM_1) {
1828 factor = 1.e4;
1829 shift = 0;
1830 return inv;
1831 }
1832 break;
1833 case GCU_SPECTRUM_UNIT_HZ:
1834 if (go_finite (freq) && newu == GCU_SPECTRUM_UNIT_PPM)
1835 factor = 1. / freq;
1836 shift = 0.;
1837 return mult;
1838 default:
1839 break;
1840 }
1841 return NULL;
1842 }
1843
OnShowIntegral()1844 void SpectrumDocument::OnShowIntegral ()
1845 {
1846 m_IntegralVisible = !m_IntegralVisible;
1847 GOStyle *style;
1848 if (m_IntegralVisible) {
1849 if (integral < 0) {
1850 integral = variables.size ();
1851 JdxVar v;
1852 double *xo, *xn[5], *yb, cur, acc;
1853 v.Name = _("Integral");
1854 v.Symbol = 'i';
1855 v.Type = GCU_SPECTRUM_TYPE_DEPENDENT;
1856 v.Unit = GCU_SPECTRUM_UNIT_MAX;
1857 v.Format = GCU_SPECTRUM_FORMAT_MAX;
1858 v.Factor = 1.;
1859 v.NbValues = (X >= 0)? variables[X].NbValues: npoints;
1860 xn[0] = new double[v.NbValues];
1861 xn[1] = new double[v.NbValues];
1862 xn[2] = new double[v.NbValues];
1863 xn[3] = new double[v.NbValues];
1864 xn[4] = new double[v.NbValues];
1865 yb = new double[v.NbValues];
1866 v.First = 0.;
1867 v.Values = new double[v.NbValues];
1868 unsigned i;
1869 double *z;
1870 if (Rp >= 0)
1871 z = variables[Rp].Values;
1872 else if (R >= 0)
1873 z = variables[R].Values;
1874 else if (Y >= 0)
1875 z = variables[Y].Values;
1876 else
1877 z = y;
1878 xo = (X >= 0 && variables[X].Values != NULL)? variables[X].Values: x;
1879 double max, delta;
1880 unsigned used = 0;
1881 go_range_max (z, v.NbValues, &max);
1882 max *= 0.005;
1883 v.Values[0] = 0.;
1884 for (i = 1; i < v.NbValues; i++) {
1885 delta = 0.5 * (z[i - 1] + z[i]);
1886 v.Values[i] = v.Values[i - 1] + delta;
1887 if (delta < max) {
1888 cur = xn[0][used] = xo[i];
1889 acc = xn[1][used] = cur * cur;
1890 xn[2][used] = (acc *= cur);
1891 xn[3][used] = (acc *= cur);
1892 xn[4][used] = acc * cur;
1893 yb[used] = (used > 0)? yb[used - 1] + delta: delta;
1894 used++;
1895 }
1896 }
1897 go_regression_stat_t reg;
1898 double res[6];
1899 go_linear_regression (xn, 5, yb, used, true, res, ®);
1900 for (i = 0; i < v.NbValues; i++) {
1901 cur = xo[i];
1902 acc = cur * cur;
1903 v.Values[i] -= res[0] + res[1] * cur + res[2] * acc;
1904 v.Values[i] -= res[3] * (acc *= cur);
1905 v.Values[i] -= res[4] * (acc *= cur);
1906 v.Values[i] -= res[5] * cur * acc;
1907 }
1908 if (xo[1] > xo[0])
1909 for (i = 0; i < v.NbValues; i++)
1910 v.Values[i] = -v.Values[i];
1911 g_free (reg.se);
1912 g_free (reg.t);
1913 g_free (reg.xbar);
1914 v.Last = v.Max = v.Values[v.NbValues - 1];
1915 v.Min = 0.;
1916 v.Series = m_View->NewSeries (true);
1917 GOData *godata;
1918 godata = go_data_vector_val_new (xo, npoints, NULL);
1919 gog_series_set_dim (v.Series, 0, godata, NULL);
1920 godata = go_data_vector_val_new (v.Values, v.NbValues, NULL);
1921 gog_series_set_dim (v.Series, 1, godata, NULL);
1922 GOStyledObject *axis = GO_STYLED_OBJECT (g_object_new (GOG_TYPE_AXIS, "major-tick-labeled", false, NULL));
1923 GogPlot *plot = gog_series_get_plot (v.Series);
1924 GogObject *chart = GOG_OBJECT (gog_object_get_parent (GOG_OBJECT (plot)));
1925 gog_object_add_by_name (chart, "Y-Axis", GOG_OBJECT (axis));
1926 gog_plot_set_axis (plot, GOG_AXIS (axis));
1927 style = go_styled_object_get_style (axis);
1928 style->line.auto_dash = false;
1929 style->line.dash_type = GO_LINE_NONE;
1930 style = go_styled_object_get_style (GO_STYLED_OBJECT (v.Series));
1931 style->line.auto_dash = false;
1932 style->line.auto_color = false;
1933 style->line.color = GO_COLOR_RED;
1934 variables.push_back (v);
1935 delete [] xn[0];
1936 delete [] xn[1];
1937 delete [] xn[2];
1938 delete [] xn[3];
1939 delete [] xn[4];
1940 delete [] yb;
1941 } else
1942 style = go_styled_object_get_style (GO_STYLED_OBJECT (variables[integral].Series));
1943 // show the series
1944 style->line.dash_type = GO_LINE_SOLID;
1945 gog_object_request_update (GOG_OBJECT (variables[integral].Series));
1946 } else {
1947 // hide the series
1948 style = go_styled_object_get_style (GO_STYLED_OBJECT (variables[integral].Series));
1949 style->line.dash_type = GO_LINE_NONE;
1950 gog_object_request_update (GOG_OBJECT (variables[integral].Series));
1951 }
1952 }
1953
OnTransformFID(G_GNUC_UNUSED GtkButton * btn)1954 void SpectrumDocument::OnTransformFID (G_GNUC_UNUSED GtkButton *btn)
1955 {
1956 double *re = variables[R].Values, *im = variables[I].Values;
1957 unsigned n = 2;
1958 while (n < npoints)
1959 n <<= 1;
1960 go_complex *fid = new go_complex[n], *sp;
1961 unsigned i;
1962 for (i = 0; i < npoints; i++) {
1963 // assuming we have as many real, imaginary and time values
1964 fid[i].re = re[i];
1965 fid[i].im = im[i];
1966 }
1967 for (; i < n; i++) {
1968 // fill with zeros
1969 fid[i].re = fid[i].im = 0.;
1970 }
1971 //we make no apodization at the moment
1972 go_fourier_fft (fid, n, 1, &sp, false);
1973 delete [] fid;
1974 // copy the unphased data to Rt and It (t for transformed)
1975 JdxVar vr, vi, rp, xt;
1976 vr.Name = _("Real transformed data");
1977 vr.Symbol = 't';
1978 vr.Type = GCU_SPECTRUM_TYPE_DEPENDENT;
1979 vr.Unit = GCU_SPECTRUM_UNIT_MAX;
1980 vr.Format = GCU_SPECTRUM_FORMAT_MAX;
1981 vr.Factor = 1.;
1982 vr.NbValues = n;
1983 vr.Values = new double[n];
1984 vi.Name = _("Imaginary transformed data");
1985 vi.Symbol = 'u';
1986 vi.Type = GCU_SPECTRUM_TYPE_DEPENDENT;
1987 vi.Unit = GCU_SPECTRUM_UNIT_MAX;
1988 vi.Format = GCU_SPECTRUM_FORMAT_MAX;
1989 vi.Factor = 1.;
1990 vi.NbValues = n;
1991 vi.Values = new double[n];
1992 unsigned n2 = n / 2 - 1, j;
1993 for (i = 0, j = n2; i < n2; i++, j--) {
1994 vr.Values[i] = sp[j].re;
1995 vi.Values[i] = sp[j].im;
1996 }
1997 // the value at 0 must be skipped, doing a linear interpolation
1998 vr.Values[i] = (sp[1].re + sp[n - 1].re) / 2.;
1999 vi.Values[i++] = (sp[1].im + sp[n - 1].im) / 2.;
2000 for (j = n - 1; i < n; i++, j--) {
2001 vr.Values[i] = sp[j].re;
2002 vi.Values[i] = sp[j].im;
2003 }
2004 vr.First = vr.Values[0];
2005 vr.Last = vr.Values[n - 1];
2006 go_range_min (vr.Values, n, &vr.Min);
2007 go_range_max (vr.Values, n, &vr.Max);
2008 vr.Series = NULL;
2009 Rt = variables.size ();
2010 variables.push_back (vr);
2011 vi.First = vi.Values[0];
2012 vi.Last = vi.Values[n - 1];
2013 go_range_min (vi.Values, n, &vi.Min);
2014 go_range_max (vi.Values, n, &vi.Max);
2015 vi.Series = NULL;
2016 It = variables.size ();
2017 variables.push_back (vi);
2018 // Now we need to adjust the phase (see http://www.ebyte.it/stan/Poster_EDISPA.html)
2019 double phi = 0., tau = 0., *z, maxz = 0., phiopt = 0., tauopt = 0.;
2020 z = new double[n];
2021 for (i = 0; i < n; i++) {
2022 // copy reordered data to sp
2023 sp[i].re = vr.Values[i];
2024 sp[i].im = vi.Values[i];
2025 z[i] = go_complex_mod (sp + i);
2026 if (z[i] > maxz)
2027 maxz = z[i];
2028 }
2029 // normalize the z values
2030 for (i = 0; i < n; i++)
2031 z[i] /= maxz;
2032 double c = 0.1;
2033 unsigned nmax, nmin;
2034 while (c > 0.) {
2035 nmin = n, nmax = 0;
2036 for (i = 0; i < n; i++)
2037 if (z[i] > c) {
2038 nmin = i;
2039 break;
2040 }
2041 for (i = n - 1; i > 0; i--)
2042 if (z[i] > c) {
2043 nmax = i;
2044 break;
2045 }
2046 if ((nmax - nmin) > n / 10) // 10 is arbitrary, but should be not too large
2047 break;
2048 c /= 2.;
2049 }
2050 // make a list of indices with z greater than c
2051 std::list <unsigned> restricted;
2052 for (i = 0; i < n; i++)
2053 if (z[i] > c)
2054 restricted.push_back (i);
2055 // evaluate the predictor in c, since the value is not used anymore
2056 double maxc = 0., maxk = 0., p, phis[41];
2057 unsigned k;
2058 std::list <unsigned>::iterator it, itend = restricted.end ();
2059 for (k = 0; k < 41; k++) {
2060 tau = -1. + k * .1;
2061 maxk = 0.;
2062 for (phi = 0; phi < 2 * M_PI; phi += 10. / 180. * M_PI) {
2063 c = 0.;
2064 for (it = restricted.begin (); it != itend; it++) {
2065 i = *it;
2066 p = phi - 2. * M_PI * tau * (n - 1 - i) / n;
2067 c += z[i] * z[i] * (sp[i].re * cos (p) - sp[i].im * sin (p)) * exp (-fabs (4. * i / n -2));
2068 }
2069 if (c > maxk) {
2070 if (c > maxc) {
2071 maxc = c;
2072 tauopt = tau;
2073 phiopt = phi;
2074 }
2075 maxk = c;
2076 phis[k] = phi;
2077 }
2078 }
2079 }
2080 // let's search more finely around the maximum
2081 // using the fact that phis[k] is a(n almost) linear function of tau
2082 // first, reevaluate the optimum phi for tauopt and previous value and next value with a step of 1°
2083 double phase = phiopt;
2084 for (phi = phase - 9. / 180. * M_PI; phi < phase + 10. / 180. * M_PI; phi += 1. / 180. * M_PI) {
2085 c = 0.;
2086 for (it = restricted.begin (); it != itend; it++) {
2087 i = *it;
2088 p = phi - 2. * M_PI * tauopt * (n - 1 - i) / n;
2089 c += z[i] * z[i] * (sp[i].re * cos (p) - sp[i].im * sin (p)) * exp (-fabs (4. * i / n -2));
2090 }
2091 if (c > maxc) {
2092 maxc = c;
2093 phiopt = phi;
2094 }
2095 }
2096 for (k = 1; k < 10; k++) {
2097 // search with lower values of tau
2098 tau = tauopt - 0.01 * k;
2099 for (phi = 0; phi < 2 * M_PI; phi += 10. / 180. * M_PI) {
2100 c = 0.;
2101 maxk = 0;
2102 for (it = restricted.begin (); it != itend; it++) {
2103 i = *it;
2104 p = phi - 2. * M_PI * tau * (n - 1 - i) / n;
2105 c += z[i] * z[i] * (sp[i].re * cos (p) - sp[i].im * sin (p)) * exp (-fabs (4. * i / n -2));
2106 }
2107 if (c > maxk) {
2108 phis[0] = phi;
2109 maxk = c;
2110 }
2111 }
2112 phase = phis[0];
2113 for (phi = phase - 9. / 180. * M_PI; phi < phase + 10. / 180. * M_PI; phi += 1. / 180. * M_PI) {
2114 c = 0.;
2115 for (it = restricted.begin (); it != itend; it++) {
2116 i = *it;
2117 p = phi - 2. * M_PI * tau * (n - 1 - i) / n;
2118 c += z[i] * z[i] * (sp[i].re * cos (p) - sp[i].im * sin (p)) * exp (-fabs (4. * i / n -2));
2119 }
2120 if (c > maxk) {
2121 maxk = c;
2122 phis[0] = phi;
2123 }
2124 }
2125 if (maxk < maxc)
2126 break;
2127 maxc = maxk;
2128 phiopt = phis[0];
2129 tauopt = tau;
2130 }
2131 if (k == 1) {
2132 for (k = 1; k < 10; k++) {
2133 // search with higher values of tau
2134 tau = tauopt + 0.01 * k;
2135 for (phi = 0; phi < 2 * M_PI; phi += 10. / 180. * M_PI) {
2136 c = 0.;
2137 maxk = 0;
2138 for (it = restricted.begin (); it != itend; it++) {
2139 i = *it;
2140 p = phi - 2. * M_PI * tau * (n - 1 - i) / n;
2141 c += z[i] * z[i] * (sp[i].re * cos (p) - sp[i].im * sin (p)) * exp (-fabs (4. * i / n -2));
2142 }
2143 if (c > maxk) {
2144 phis[0] = phi;
2145 maxk = c;
2146 }
2147 }
2148 phase = phis[0];
2149 for (phi = phase - 9. / 180. * M_PI; phi < phase + 10. / 180. * M_PI; phi += 1. / 180. * M_PI) {
2150 c = 0.;
2151 for (it = restricted.begin (); it != itend; it++) {
2152 i = *it;
2153 p = phi - 2. * M_PI * tau * (n - 1 - i) / n;
2154 c += z[i] * z[i] * (sp[i].re * cos (p) - sp[i].im * sin (p)) * exp (-fabs (4. * i / n -2));
2155 }
2156 if (c > maxk) {
2157 maxk = c;
2158 phis[0] = phi;
2159 }
2160 }
2161 if (maxk < maxc)
2162 break;
2163 maxc = maxk;
2164 phiopt = phis[0];
2165 tauopt = tau;
2166 }
2167 }
2168 g_free (sp);
2169 // set the phase real values
2170 // free what needs to be freed
2171 delete [] z;
2172 // set the corrected values
2173 rp.Values = new double[n];
2174 //store phi and tau as first and last, respectively
2175 double step = M_PI * 2. * tauopt / n;
2176 phase = phiopt - M_PI * 2. * tauopt;
2177 rp.First = phase + step;
2178 rp.Last = phiopt + n * step;
2179 for (i = 0; i < n; i++) {
2180 phase += step;
2181 rp.Values[i] = vr.Values[i] * cos (phase) - vi.Values[i] * sin (phase);
2182 }
2183 go_range_min (rp.Values, n, &rp.Min);
2184 go_range_max (rp.Values, n, &rp.Max);
2185 Rp = variables.size ();
2186 variables.push_back (rp);
2187 // add Hz and ppm variables (0 for last point, user will have to choose a reference peak)
2188 // first Hz
2189 // if we are there, we have R and I values, we should have also X, but let's check
2190 double freq, shift;
2191 if (X >= 0 && variables[X].Values != NULL)
2192 freq = 1 / (variables[X].Last - variables[X].First);
2193 else
2194 freq = 1 / (lastx - firstx);
2195 if (!go_finite (offset))
2196 offset = 0.;
2197 shift = offset - freq * (npoints - 1) / 2.;
2198 //now display the spectrum
2199 variables[R].Series = NULL;
2200 rp.Series = m_View->GetSeries ();
2201 GOData *godata = go_data_vector_val_new (rp.Values, n, NULL);
2202 gog_series_set_dim (rp.Series, 1, godata, NULL);
2203 m_View->SetAxisBounds (GOG_AXIS_Y, rp.Min, rp.Max, false);
2204 if (Xt < 0) {
2205 xt.Name = _("Chemical shift");
2206 xt.Symbol = 'X';
2207 xt.Type = GCU_SPECTRUM_TYPE_INDEPENDENT;
2208 xt.Unit = GCU_SPECTRUM_UNIT_HZ;
2209 xt.Format = GCU_SPECTRUM_FORMAT_MAX;
2210 xt.Factor = 1.;
2211 xt.NbValues = n;
2212 xt.Values = new double[n];
2213 for (i = 0; i < n; i++)
2214 xt.Values[i] = i * freq + shift;
2215 xt.Min = xt.First = xt.Values[0];
2216 xt.Max = xt.Last = xt.Values[n - 1];
2217 xt.Series = NULL;
2218 X = variables.size ();
2219 variables.push_back (xt);
2220 }
2221 godata = go_data_vector_val_new (variables[X].Values, variables[X].NbValues, NULL);
2222 gog_series_set_dim (rp.Series, 0, godata, NULL);
2223 m_SpectrumType = GCU_SPECTRUM_NMR;
2224 m_View->SetAxisBounds (GOG_AXIS_X, variables[X].Min, variables[X].Max, true);
2225 m_View->SetAxisLabel (GOG_AXIS_X, _(UnitNames[variables[X].Unit]));
2226 OnXUnitChanged (0);
2227 // remove the last widget from the option box
2228 m_View->DestroyExtraWidget ();
2229 // now add the widgets appropriate for an NMR spectrum
2230 GtkWidget *grid = gtk_grid_new (), *w;
2231 if (!gtk_check_version (3, 2, 0))
2232 gtk_grid_set_column_spacing (GTK_GRID (grid), 12);
2233 else
2234 gtk_grid_set_row_spacing (GTK_GRID (grid), 12);
2235 if (go_finite (freq)) {
2236 w = gtk_label_new (_("X unit:"));
2237 gtk_container_add (GTK_CONTAINER (grid), w);
2238 w = gtk_combo_box_text_new ();
2239 gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (w), _("Chemical shift (ppm)"));
2240 gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (w), _("Frequency (Hz)"));
2241 SpectrumUnitType unit = (X >= 0)? variables[X].Unit: m_XUnit;
2242 gtk_combo_box_set_active (GTK_COMBO_BOX (w), ((unit == GCU_SPECTRUM_UNIT_PPM)? 0: 1));
2243 g_signal_connect (w, "changed", G_CALLBACK (on_xunit_changed), this);
2244 gtk_container_add (GTK_CONTAINER (grid), w);
2245 }
2246 w = gtk_button_new_with_label (_("Show integral"));
2247 g_signal_connect (w, "clicked", G_CALLBACK (on_show_integral), this);
2248 gtk_container_add (GTK_CONTAINER (grid), w);
2249 gtk_widget_show_all (grid);
2250 m_View->AddToOptionBox (grid);
2251 }
2252
OnXAxisInvert(bool inverted)2253 void SpectrumDocument::OnXAxisInvert (bool inverted)
2254 {
2255 m_View->InvertAxis (GOG_AXIS_X, inverted);
2256 }
2257
Loaded()2258 bool SpectrumDocument::Loaded () throw (gcu::LoaderError)
2259 {
2260 bool hide_y_axis = false;
2261 SpectrumUnitType unit = GCU_SPECTRUM_UNIT_MAX;
2262 // doon't do anything for unsupported spectra
2263 switch (m_SpectrumType) {
2264 case GCU_SPECTRUM_NMR: {
2265 if (x == NULL && X >= 0 && variables[X].Values == NULL)
2266 return false;
2267 // fix origin
2268 if (go_finite (offset)) {
2269 unsigned i;
2270 if (x) {
2271 double d = offset * freq - maxx;
2272 maxx += d;
2273 minx += d;
2274 firstx += d;
2275 lastx += d;
2276 for (i = 0; i < npoints; i++)
2277 x[i] += d;
2278 } else if (X < 0) {
2279 JdxVar xt;
2280 xt.Name = _("Chemical shift");
2281 xt.Symbol = 'X';
2282 xt.Type = GCU_SPECTRUM_TYPE_INDEPENDENT;
2283 xt.Unit = GCU_SPECTRUM_UNIT_HZ;
2284 xt.Format = GCU_SPECTRUM_FORMAT_MAX;
2285 xt.Factor = 1.;
2286 xt.NbValues = npoints;
2287 xt.Values = new double[npoints];
2288 double freq = (maxx - minx) / npoints, shift = (maxx - minx) / 2. - offset;
2289 maxx -= shift;
2290 minx -= shift;
2291 for (i = 0; i < npoints; i++)
2292 xt.Values[i] = i * freq + minx;
2293 xt.Min = xt.First = xt.Values[0];
2294 xt.Max = xt.Last = xt.Values[npoints - 1];
2295 xt.Series = NULL;
2296 X = variables.size ();
2297 variables.push_back (xt);
2298 OnXUnitChanged (0);
2299 minx = variables[X].Min;
2300 maxx = variables[X].Max;
2301 } else {
2302 double d = offset * freq - variables[X].Max;
2303 maxx = variables[X].Max += d;
2304 minx = variables[X].Min += d;
2305 variables[X].First += d;
2306 variables[X].Last += d;
2307 for (i = 0; i < npoints; i++)
2308 variables[X].Values[i] += d;
2309 }
2310 } else if (go_finite (refpoint)) {
2311 unsigned i;
2312 double d = -refpoint;
2313 if (x) {
2314 maxx += d;
2315 minx += d;
2316 firstx += d;
2317 lastx += d;
2318 for (i = 0; i < npoints; i++)
2319 x[i] += d;
2320 } else {
2321 maxx = variables[X].Max += d;
2322 minx = variables[X].Min += d;
2323 variables[X].First += d;
2324 variables[X].Last += d;
2325 for (i = 0; i < npoints; i++)
2326 variables[X].Values[i] += d;
2327 }
2328 }
2329 // add some widgets to the option box
2330 GtkWidget *grid = gtk_grid_new (), *w;
2331 if (!gtk_check_version (3, 2, 0))
2332 gtk_grid_set_column_spacing (GTK_GRID (grid), 12);
2333 else
2334 gtk_grid_set_row_spacing (GTK_GRID (grid), 12);
2335 if (go_finite (freq)) {
2336 w = gtk_label_new (_("X unit:"));
2337 gtk_container_add (GTK_CONTAINER (grid), w);
2338 w = gtk_combo_box_text_new ();
2339 gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (w), _("Chemical shift (ppm)"));
2340 gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (w), _("Frequency (Hz)"));
2341 SpectrumUnitType unit = (X >= 0)? variables[X].Unit: m_XUnit;
2342 gtk_combo_box_set_active (GTK_COMBO_BOX (w), ((unit == GCU_SPECTRUM_UNIT_PPM)? 0: 1));
2343 g_signal_connect (w, "changed", G_CALLBACK (on_xunit_changed), this);
2344 gtk_container_add (GTK_CONTAINER (grid), w);
2345 }
2346 w = gtk_button_new_with_label (_("Show integral"));
2347 g_signal_connect (w, "clicked", G_CALLBACK (on_show_integral), this);
2348 gtk_container_add (GTK_CONTAINER (grid), w);
2349 gtk_widget_show_all (grid);
2350 m_View->AddToOptionBox (grid);
2351 hide_y_axis = true;
2352 break;
2353 }
2354 case GCU_SPECTRUM_NMR_FID: {
2355 if (x == NULL && X >= 0 && variables[X].Values == NULL)
2356 return false;
2357 else if (x == NULL && X < 0) {
2358 x = new double[npoints];
2359 deltax = (maxx - minx) / (npoints - 1);
2360 for (unsigned i = 0; i < npoints;i++)
2361 x[i] = minx + i * deltax;
2362 firstx = 0;
2363 lastx = x[npoints - 1];
2364 }
2365 if (R >= 0 && I >= 0) {
2366 GtkWidget *grid = gtk_grid_new ();
2367 if (!gtk_check_version (3, 2, 0))
2368 gtk_grid_set_column_spacing (GTK_GRID (grid), 12);
2369 else
2370 gtk_grid_set_row_spacing (GTK_GRID (grid), 12);
2371 GtkWidget *w = gtk_button_new_with_label (_("Transform to spectrum"));
2372 g_signal_connect (w, "clicked", G_CALLBACK (on_transform_fid), this);
2373 if (!go_finite (offset))
2374 gtk_widget_set_sensitive (w, false);
2375 gtk_container_add (GTK_CONTAINER (grid), w);
2376 gtk_widget_show_all (grid);
2377 m_View->AddToOptionBox (grid);
2378 }
2379 hide_y_axis = true;
2380 break;
2381 }
2382 case GCU_SPECTRUM_INFRARED:
2383 case GCU_SPECTRUM_RAMAN:
2384 unit = GCU_SPECTRUM_UNIT_MICROMETERS;
2385 // case GCU_SPECTRUM_INFRARED_PEAK_TABLE:
2386 // case GCU_SPECTRUM_INFRARED_INTERFEROGRAM:
2387 // case GCU_SPECTRUM_INFRARED_TRANSFORMED:
2388 case GCU_SPECTRUM_UV_VISIBLE:
2389 if (x == NULL && X > 0 && variables[X].Values == NULL)
2390 return false;
2391 else {
2392 if (unit == GCU_SPECTRUM_UNIT_MAX)
2393 unit = GCU_SPECTRUM_UNIT_NANOMETERS;
2394 // add some widgets to the option box
2395 GtkWidget *grid = gtk_grid_new (), *w;
2396 if (!gtk_check_version (3, 2, 0))
2397 gtk_grid_set_column_spacing (GTK_GRID (grid), 12);
2398 else
2399 gtk_grid_set_row_spacing (GTK_GRID (grid), 12);
2400 w = gtk_label_new (_("X unit:"));
2401 gtk_container_add (GTK_CONTAINER (grid), w);
2402 w = gtk_combo_box_text_new ();
2403 GList *cells = gtk_cell_layout_get_cells (GTK_CELL_LAYOUT (w));
2404 if (cells && cells->data) {
2405 /* set "markup" as the target property */
2406 gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (w), GTK_CELL_RENDERER (cells->data),
2407 "markup", 0, NULL);
2408 }
2409 if (unit == GCU_SPECTRUM_UNIT_NANOMETERS)
2410 gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (w), _("Wave length (nm)"));
2411 else
2412 gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (w), _("Wave length (µm)"));
2413 gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (w), _("Wavenumber (cm<sup>−1</sup>)"));
2414 SpectrumUnitType unit = (X >= 0)? variables[X].Unit: m_XUnit;
2415 gtk_combo_box_set_active (GTK_COMBO_BOX (w), ((unit == GCU_SPECTRUM_UNIT_CM_1)? 1: 0));
2416 g_signal_connect (w, "changed", G_CALLBACK (on_xunit_changed), this);
2417 gtk_container_add (GTK_CONTAINER (grid), w);
2418 m_XAxisInvertBtn = gtk_check_button_new_with_label (_("Invert X Axis"));
2419 m_XAxisInvertSgn = g_signal_connect (m_XAxisInvertBtn, "toggled", G_CALLBACK (on_xaxis_invert), this);
2420 gtk_container_add (GTK_CONTAINER (grid), m_XAxisInvertBtn);
2421 unit = (Y >= 0)? variables[Y].Unit: m_YUnit;
2422 if (unit == GCU_SPECTRUM_UNIT_ABSORBANCE || unit == GCU_SPECTRUM_UNIT_TRANSMITTANCE) {
2423 w = gtk_separator_new (GTK_ORIENTATION_VERTICAL);
2424 gtk_container_add (GTK_CONTAINER (grid), w);
2425 w = gtk_label_new (_("Y unit:"));
2426 gtk_container_add (GTK_CONTAINER (grid), w);
2427 w = gtk_combo_box_text_new ();
2428 gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (w), _("Absorbance"));
2429 gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (w), _("Transmittance"));
2430 gtk_combo_box_set_active (GTK_COMBO_BOX (w), ((unit == GCU_SPECTRUM_UNIT_ABSORBANCE)? 0: 1));
2431 g_signal_connect (w, "changed", G_CALLBACK (on_yunit_changed), this);
2432 gtk_container_add (GTK_CONTAINER (grid), w);
2433 }
2434 gtk_widget_show_all (grid);
2435 m_View->AddToOptionBox (grid);
2436 }
2437 break;
2438 // case GCU_SPECTRUM_NMR_PEAK_TABLE:
2439 // case GCU_SPECTRUM_NMR_PEAK_ASSIGNMENTS:
2440 case GCU_SPECTRUM_MASS:
2441 break;
2442 default:
2443 return false;
2444 }
2445 m_Empty = npoints == 0;
2446 GOData *godata;
2447 GogSeries *series = m_View->GetSeries ();
2448 if (X >= 0 && variables[X].Values != NULL) {
2449 godata = go_data_vector_val_new (variables[X].Values, npoints, NULL);
2450 m_XUnit = variables[X].Unit;
2451 }
2452 else
2453 godata = go_data_vector_val_new (x, npoints, NULL);
2454 gog_series_set_dim (series, 0, godata, NULL);
2455 if (Y >= 0 && variables[Y].Values != NULL) {
2456 godata = go_data_vector_val_new (variables[Y].Values, npoints, NULL);
2457 m_YUnit = variables[Y].Unit;
2458 } else if (R >= 0 && variables[R].Values != NULL) {
2459 godata = go_data_vector_val_new (variables[R].Values, npoints, NULL);
2460 m_YUnit = variables[R].Unit;
2461 } else
2462 godata = go_data_vector_val_new (y, npoints, NULL);
2463 gog_series_set_dim (series, 1, godata, NULL);
2464 /* invert X-axis if needed */
2465 bool invert_axis = false;
2466 switch (m_XUnit) {
2467 case GCU_SPECTRUM_UNIT_CM_1:
2468 case GCU_SPECTRUM_UNIT_PPM:
2469 invert_axis = true;
2470 break;
2471 case GCU_SPECTRUM_UNIT_HZ:
2472 if (m_SpectrumType == GCU_SPECTRUM_NMR)
2473 invert_axis = true;
2474 break;
2475 default:
2476 break;
2477 }
2478 if (m_XAxisInvertBtn) {
2479 g_signal_handler_block (m_XAxisInvertBtn, m_XAxisInvertSgn);
2480 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (m_XAxisInvertBtn), invert_axis);
2481 g_signal_handler_unblock (m_XAxisInvertBtn, m_XAxisInvertSgn);
2482 }
2483 m_View->SetAxisBounds (GOG_AXIS_X, minx, maxx, invert_axis);
2484 m_View->SetAxisBounds (GOG_AXIS_Y, miny, maxy, false);
2485 if (hide_y_axis)
2486 m_View->ShowAxis (GOG_AXIS_Y, false);
2487 /* Add axes labels */
2488 if (m_XUnit < GCU_SPECTRUM_UNIT_MAX)
2489 m_View->SetAxisLabel (GOG_AXIS_X, _(UnitNames[m_XUnit]));
2490 if (m_YUnit < GCU_SPECTRUM_UNIT_MAX)
2491 m_View->SetAxisLabel (GOG_AXIS_Y, _(UnitNames[m_YUnit]));
2492 return true;
2493 }
2494
SetProperty(unsigned property,char const * value)2495 bool SpectrumDocument::SetProperty (unsigned property, char const *value)
2496 {
2497 istringstream is (value);
2498 switch (property) {
2499 case GCU_PROP_DOC_TITLE:
2500 SetTitle (value);
2501 break;
2502 case GCU_PROP_SPECTRUM_TYPE:
2503 m_SpectrumType = get_spectrum_type_from_string (value);
2504 break;
2505 case GCU_PROP_SPECTRUM_NPOINTS:
2506 is >> npoints;
2507 break;
2508 case GCU_PROP_SPECTRUM_DATA_X:
2509 break;
2510 case GCU_PROP_SPECTRUM_DATA_Y:
2511 break;
2512 case GCU_PROP_SPECTRUM_DATA_REAL: {
2513 if (npoints == 0 || R >= 0)
2514 return false;
2515 JdxVar vr;
2516 vr.Name = _("Real data");
2517 vr.Symbol = 'r';
2518 vr.Type = GCU_SPECTRUM_TYPE_DEPENDENT;
2519 vr.Unit = GCU_SPECTRUM_UNIT_MAX;
2520 vr.Format = GCU_SPECTRUM_FORMAT_MAX;
2521 vr.Factor = 1.;
2522 vr.NbValues = npoints;
2523 vr.Values = new double[npoints];
2524 for (unsigned i = 0; i < npoints; i++)
2525 is >> vr.Values[i];
2526 vr.First = vr.Values[0];
2527 vr.Last = vr.Values[npoints - 1];
2528 go_range_min (vr.Values, npoints, &vr.Min);
2529 go_range_max (vr.Values, npoints, &vr.Max);
2530 vr.Series = NULL;
2531 Y = R = variables.size ();
2532 variables.push_back (vr);
2533 break;
2534 }
2535 case GCU_PROP_SPECTRUM_DATA_IMAGINARY: {
2536 if (npoints == 0 || I >= 0)
2537 return false;
2538 JdxVar vi;
2539 vi.Name = _("Imaginary data");
2540 vi.Symbol = 'i';
2541 vi.Type = GCU_SPECTRUM_TYPE_DEPENDENT;
2542 vi.Unit = GCU_SPECTRUM_UNIT_MAX;
2543 vi.Format = GCU_SPECTRUM_FORMAT_MAX;
2544 vi.Factor = 1.;
2545 vi.NbValues = npoints;
2546 vi.Values = new double[npoints];
2547 for (unsigned i = 0; i < npoints; i++)
2548 is >> vi.Values[i];
2549 vi.First = vi.Values[0];
2550 vi.Last = vi.Values[npoints - 1];
2551 go_range_min (vi.Values, npoints, &vi.Min);
2552 go_range_max (vi.Values, npoints, &vi.Max);
2553 vi.Series = NULL;
2554 I = variables.size ();
2555 variables.push_back (vi);
2556 break;
2557 }
2558 case GCU_PROP_SPECTRUM_X_UNIT:
2559 m_XUnit = (SpectrumUnitType) get_spectrum_data_from_string (value, Units, GCU_SPECTRUM_UNIT_MAX);
2560 break;
2561 case GCU_PROP_SPECTRUM_X_MIN:
2562 is >> minx;
2563 break;
2564 case GCU_PROP_SPECTRUM_X_MAX:
2565 is >> maxx;
2566 break;
2567 case GCU_PROP_SPECTRUM_X_OFFSET:
2568 is >> offset;
2569 break;
2570 case GCU_PROP_SPECTRUM_NMR_FREQ:
2571 is >> freq;
2572 break;
2573 default:
2574 return false;
2575 }
2576 return true;
2577 }
2578
2579 } // nampespace gcu
2580