build: update parfait spec with a parfait-agent package
[pcp.git] / src / pmview / barobj.cpp
blob5e12abd307201a8f131c4ffdcbaa80a1e93c1dd6
1 /*
2 * Copyright (c) 1997 Silicon Graphics, Inc. All Rights Reserved.
3 * Copyright (c) 2009 Aconex. All Rights Reserved.
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 * for more details.
15 #include <Inventor/nodes/SoBaseColor.h>
16 #include <Inventor/nodes/SoScale.h>
17 #include <Inventor/nodes/SoSeparator.h>
18 #include <Inventor/nodes/SoTranslation.h>
19 #include <Inventor/nodes/SoTransform.h>
21 #include "barobj.h"
22 #include "colorlist.h"
23 #include "yscalemod.h"
24 #include "colormod.h"
25 #include "colorscalemod.h"
26 #include "text.h"
27 #include "defaultobj.h"
29 #include <iostream>
30 using namespace std;
32 BarObj::~BarObj()
36 BarObj::BarObj(ViewObj::Shape shape,
37 BarMod::Direction dir,
38 BarMod::Modulation mod,
39 BarMod::Grouping group,
40 bool baseFlag,
41 const DefaultObj &defaults,
42 int x, int y,
43 int cols, int rows,
44 BaseObj::Alignment align)
45 : ModObj(baseFlag, defaults, x, y, cols, rows, align),
46 _shape(shape),
47 _dir(dir),
48 _mod(mod),
49 _group(group),
50 _width(0),
51 _depth(0),
52 _xSpace(defaults.barSpaceX()),
53 _zSpace(defaults.barSpaceZ()),
54 _labelSpace(defaults.barSpaceLabel()),
55 _bars(0),
56 _metDir(towards),
57 _metLabels(new QStringList),
58 _instDir(away),
59 _instLabels(new QStringList)
61 _objtype |= BAROBJ;
63 int i;
64 for (i = 0; i < numSides; i++)
65 _margins[i] = 0.0;
66 _labelColor[0] = defaults.labelColor(0);
67 _labelColor[1] = defaults.labelColor(1);
68 _labelColor[2] = defaults.labelColor(2);
71 void
72 BarObj::finishedAdd()
74 const ColorSpec *colSpec = NULL;
75 SoNode *object = ViewObj::object(_shape);
76 SoSeparator *labelSep = NULL;
77 SoSeparator *metricSep = NULL;
78 SoSeparator *instSep = NULL;
79 SoSeparator *barSep = new SoSeparator;
80 SoSeparator *baseSep = new SoSeparator;
81 SoTranslation *objTran = new SoTranslation;
82 SoTranslation *barTran = new SoTranslation;
83 SoTranslation *baseTran = new SoTranslation;
84 SoTranslation *modTran = new SoTranslation;
85 ColorScale *colScale = NULL;
86 LabelSide metSide = left;
87 LabelSide instSide = left;
88 Text **metText = NULL;
89 Text **instText = NULL;
90 int i;
91 int max = 0;
92 int numMetLabels = 0;
93 int numInstLabels = 0;
95 #ifdef PCP_DEBUG
96 if (pmDebug & DBG_TRACE_APPL0)
97 cerr << "BarObj::finishedAdd:" << endl;
98 #endif
100 if (_metrics.numMetrics() == 0) {
101 BaseObj::addBase(_root);
102 pmprintf("%s: Error: Bar object has no metrics\n",
103 pmProgname);
104 _length = 0;
105 _width = baseWidth();
106 _depth = baseDepth();
107 return;
110 _root->addChild(objTran);
112 if (_metLabels->size() || _instLabels->size()) {
113 labelSep = new SoSeparator;
114 _root->addChild(labelSep);
115 SoBaseColor *base = new SoBaseColor;
116 base->rgb.setValue(_labelColor[0], _labelColor[1], _labelColor[2]);
117 labelSep->addChild(base);
119 _root->addChild(barSep);
120 barSep->addChild(barTran);
121 barSep->addChild(baseSep);
122 baseSep->addChild(baseTran);
123 barSep->addChild(modTran);
124 BaseObj::addBase(baseSep);
126 // Determine color mapping
128 if (_colors.size())
129 colSpec = theColorLists.list((const char *)_colors.toLatin1());
131 if (colSpec != NULL) {
132 if (colSpec->_scale) {
133 if (_mod == BarMod::yScale) {
134 pmprintf("%s: Warning: Color scale ignored for Y-Scale Bar object.\n",
135 pmProgname);
137 else {
138 if (colSpec->_list.size() == 0)
139 colScale = new ColorScale(0.0, 0.0, 1.0);
140 else {
141 colScale = new ColorScale(*(colSpec->_list[0]));
142 for (i = 1; i < colSpec->_list.size(); i++)
143 colScale->add(new ColorStep(*(colSpec->_list[i]),
144 colSpec->_max[i]));
148 else if (_mod == BarMod::color || _mod == BarMod::colYScale) {
149 pmprintf("%s: Warning: Expected color scale for color modulated Bar object.\n",
150 pmProgname);
152 if (colSpec->_list.size() == 0)
153 colScale = new ColorScale(0.0, 0.0, 1.0);
154 else
155 colScale = new ColorScale(*(colSpec->_list[0]));
158 else {
159 pmprintf("%s: Warning: No colours specified for Bar objects, defaulting to blue.\n",
160 pmProgname);
162 if (_mod == BarMod::color || _mod == BarMod::colYScale)
163 colScale = new ColorScale(0.0, 0.0, 1.0);
166 if (_mod == BarMod::yScale) {
167 if (colSpec != NULL)
168 for (i = 0; i < colSpec->_list.size(); i++)
169 _metrics.add(*(colSpec->_list)[i]);
170 _metrics.resolveColors(MetricList::perMetric);
173 // Generate Bar Modulate Object
174 if (_mod == BarMod::yScale)
175 _bars = new BarMod(&_metrics, object, _dir, _group,
176 (float)_length, (float)_maxHeight, (float)_length,
177 (float)_xSpace, (float)_zSpace);
178 else {
179 _bars = new BarMod(&_metrics, *colScale, object, _dir, _mod, _group,
180 (float)_length, (float)_maxHeight, (float)_length,
181 (float)_xSpace, (float)_zSpace);
184 barSep->addChild(_bars->root());
185 BaseObj::add(_bars);
187 // Generate Labels
189 if (_metLabels->size()) {
190 if (_dir == BarMod::instPerRow)
191 if (_metDir == away)
192 metSide = below;
193 else
194 metSide = above;
195 else
196 if (_metDir == away)
197 metSide = right;
198 else
199 metSide = left;
201 metricSep = new SoSeparator;
202 labelSep->addChild(metricSep);
204 if (_metLabels->size() < _metrics.numMetrics())
205 numMetLabels = _metLabels->size();
206 else
207 numMetLabels = _metrics.numMetrics();
209 metText = calcLabels(*_metLabels, metSide, numMetLabels);
212 if (_instLabels->size()) {
213 if (_dir == BarMod::instPerCol) {
214 max = _bars->cols();
215 if (_instDir == away)
216 instSide = below;
217 else
218 instSide = above;
220 else {
221 max = _bars->rows();
222 if (_instDir == away)
223 instSide = right;
224 else
225 instSide = left;
228 instSep = new SoSeparator;
229 labelSep->addChild(instSep);
231 if (_instLabels->size() < max)
232 numInstLabels = _instLabels->size();
233 else
234 numInstLabels = max;
236 instText = calcLabels(*_instLabels, instSide, numInstLabels);
239 // Width and depth of bars only, effects of labels added later
241 _width = _bars->width();
242 _depth = _bars->depth();
244 // Insert the labels
246 if (numMetLabels)
247 metricSep->addChild(doLabels(metText, metSide, numMetLabels));
249 if (numInstLabels)
250 instSep->addChild(doLabels(instText, instSide, numInstLabels));
252 // Work out where the bars live
254 _bars->regenerate(_length, _length, _xSpace, _zSpace);
255 _width = _bars->width();
256 _depth = _bars->depth();
258 baseTran->translation.setValue(_width / 2.0, 0.0, _depth / 2.0);
260 _width += (u_int32_t)(baseWidth() + _margins[left] + _margins[right]+0.5);
261 _depth += (u_int32_t)(baseDepth() + _margins[above] + _margins[below]+0.5);
263 objTran->translation.setValue((_width / -2.0), 0.0, (_depth / -2.0));
265 barTran->translation.setValue(_margins[left] + borderX(), 0.0,
266 _margins[above] + borderZ());
269 modTran->translation.setValue(0.0,
270 (BaseObj::state() ? baseHeight() : 0.0),
271 0.0);
273 #ifdef PCP_DEBUG
274 if (pmDebug & DBG_TRACE_APPL0)
275 cerr << "BarObj::finishedAdd: metric list = " << endl
276 << _metrics << endl;
277 #endif
279 if (_metrics.numMetrics())
280 ViewObj::theNumModObjects++;
282 // Cleanup
284 if (colScale)
285 delete colScale;
286 delete _metLabels;
287 delete _instLabels;
290 void
291 BarObj::setTran(float xTran, float zTran, int setWidth, int setDepth)
293 BaseObj::setBaseSize(width() - _margins[left] - _margins[right],
294 depth() - _margins[above] - _margins[below]);
295 BaseObj::setTran(xTran + (width() / 2.0),
296 zTran + (depth() / 2.0),
297 setWidth, setDepth);
300 QTextStream&
301 operator<<(QTextStream& os, BarObj const& rhs)
303 rhs.display(os);
304 return os;
307 void
308 BarObj::display(QTextStream& os) const
310 BaseObj::display(os);
312 if (_bars == NULL) {
313 os << "No valid metrics" << endl;
314 return;
317 os << ", dir = "
318 << (_dir == BarMod::instPerCol ? "instPerCol" : "instPerRow")
319 << ", length = " << _length << ", xSpace = " << _xSpace << ", zSpace = "
320 << _zSpace << ", labelSpace = " << _labelSpace << ", rows = " << _rows
321 << ", cols = " << _cols << ", num bars = " << _bars->numBars()
322 << ", shape = ";
323 ViewObj::dumpShape(os, _shape);
324 os << ", margins: left = " << _margins[left] << ", right = "
325 << _margins[right] << ", above = " << _margins[above]
326 << ", below = " << _margins[below];
329 const char*
330 BarObj::name() const
332 static QString myName;
334 if (myName.size() == 0) {
335 if (_bars == NULL)
336 myName = "Invalid bar object";
337 else {
338 myName = _bars->modStr();
339 myName.append(" Bar Object (");
340 myName.append(_bars->dirStr());
341 myName.append(QChar(')'));
345 return (const char *)myName.toLatin1();
348 Text **
349 BarObj::calcLabels(const QStringList &labels, LabelSide side, int numLabels)
351 Text **text = NULL;
352 int i;
353 int maxWidth = 0;
354 int maxDepth = 0;
356 text= new Text*[numLabels];
358 #ifdef PCP_DEBUG
359 if (pmDebug & DBG_TRACE_APPL0) {
360 cerr << "BarObj::calcLabels: " << numLabels << " labels on the ";
361 switch(side) {
362 case left:
363 cerr << "left";
364 break;
365 case right:
366 cerr << "right";
367 break;
368 case above:
369 cerr << "above";
370 break;
371 case below:
372 cerr << "below";
373 break;
375 cerr << " side" << endl;
377 #endif
379 // Create the text objects so that we know how big they are
381 for (i = 0; i < numLabels; i++) {
382 if (side == above || side == below)
383 text[i] = new Text(labels[i], Text::down, Text::medium);
384 else
385 text[i] = new Text(labels[i], Text::right, Text::medium);
387 if (text[i]->width() > maxWidth)
388 maxWidth = text[i]->width();
389 if (text[i]->depth() > maxDepth)
390 maxDepth = text[i]->depth();
393 #ifdef PCP_DEBUG
394 if (pmDebug & DBG_TRACE_APPL0)
395 cerr << "BarObj::calcLabels: maxWidth = " << maxWidth
396 << ", maxDepth = " << maxDepth << endl;
397 #endif
399 // Determine if the size of the bars will need to be increased
401 if (side == above || side == below) {
402 _margins[side] = maxDepth + _labelSpace;
403 if (maxWidth > _length) {
404 _length = maxWidth;
406 #ifdef PCP_DEBUG
407 if (pmDebug & DBG_TRACE_APPL0)
408 cerr << "BarObj::calcLabels: length (width) increased to "
409 << _length << endl;
410 #endif
414 else {
415 _margins[side] = maxWidth + _labelSpace;
416 if (maxDepth > _length) {
417 _length = maxDepth;
420 #ifdef PCP_DEBUG
421 if (pmDebug & DBG_TRACE_APPL0)
422 cerr << "BarObj::calcLabels: length (depth) increased to "
423 << _length << endl;
424 #endif
427 return text;
430 SoNode *
431 BarObj::doLabels(Text **text, LabelSide side, int numLabels)
433 SoSeparator *sep = new SoSeparator;
434 SoTranslation *tran = new SoTranslation;
435 int i;
436 int maxWidth = 0;
437 int maxDepth = 0;
439 #ifdef PCP_DEBUG
440 if (pmDebug & DBG_TRACE_APPL0) {
441 cerr << "BarObj::doLabels: " << numLabels << " labels on the ";
442 switch(side) {
443 case left:
444 cerr << "left";
445 break;
446 case right:
447 cerr << "right";
448 break;
449 case above:
450 cerr << "above";
451 break;
452 case below:
453 cerr << "below";
454 break;
456 cerr << " side" << endl;
458 #endif
460 sep->addChild(tran);
462 // Determine the translation to the first label, subsequent labels
463 // are translated from the first
465 maxWidth = _length + _xSpace;
466 maxDepth = _length + _zSpace;
468 switch (side) {
469 case left:
470 tran->translation.setValue(_margins[left] - _labelSpace, 0.0,
471 _margins[above] + borderZ());
472 break;
473 case right:
474 tran->translation.setValue(
475 _margins[left] + _width + baseWidth() + _labelSpace,
476 0.0, _margins[above] + borderZ());
477 break;
478 case above:
479 tran->translation.setValue(_margins[left] + borderX(), 0.0,
480 _margins[above] - _labelSpace);
481 break;
482 case below:
483 tran->translation.setValue(_margins[left] + borderX(), 0.0,
484 _margins[above] + _depth + baseDepth() + _labelSpace);
485 break;
486 default:
487 break;
490 #ifdef PCP_DEBUG
491 if (pmDebug & DBG_TRACE_APPL0) {
492 float x, y, z;
493 tran->translation.getValue().getValue(x, y, z);
494 cerr << "BarObj::doLabels: translation set to " << x << ',' << y
495 << ',' << z << endl;
497 #endif
499 // Add each label to the scene graph
501 for (i = 0; i < numLabels; i++) {
502 SoSeparator *labelSep = new SoSeparator;
503 sep->addChild(labelSep);
505 SoTranslation *labelTran = new SoTranslation;
506 labelSep->addChild(labelTran);
508 switch (side) {
509 case left:
510 labelTran->translation.setValue(0.0,
511 0.0,
512 (maxDepth * i) + ((_length - (float)text[i]->depth())/ 2.0));
513 break;
514 case right:
515 labelTran->translation.setValue(text[i]->width(), 0.0,
516 (maxDepth * i) + ((_length - (float)text[i]->depth())/ 2.0));
517 break;
518 case above:
519 labelTran->translation.setValue(
520 (maxWidth * i) + ((_length - (float)text[i]->width())/ 2.0),
521 0.0, 0.0);
522 break;
523 case below:
524 labelTran->translation.setValue(
525 (maxWidth * i) + ((_length - (float)text[i]->width())/ 2.0),
526 0.0, text[i]->depth());
527 break;
528 default:
529 break;
532 labelSep->addChild(text[i]->root());
535 // Do not delete contents, just the array pointer
536 delete [] text;
538 return sep;