summaryrefslogtreecommitdiffstats
path: root/tkblt/generic/tkbltGrElemBar.C
diff options
context:
space:
mode:
Diffstat (limited to 'tkblt/generic/tkbltGrElemBar.C')
-rw-r--r--tkblt/generic/tkbltGrElemBar.C1315
1 files changed, 1315 insertions, 0 deletions
diff --git a/tkblt/generic/tkbltGrElemBar.C b/tkblt/generic/tkbltGrElemBar.C
new file mode 100644
index 0000000..6698760
--- /dev/null
+++ b/tkblt/generic/tkbltGrElemBar.C
@@ -0,0 +1,1315 @@
+/*
+ * Smithsonian Astrophysical Observatory, Cambridge, MA, USA
+ * This code has been modified under the terms listed below and is made
+ * available under the same terms.
+ */
+
+/*
+ * Copyright 1993-2004 George A Howlett.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include <float.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <cmath>
+
+#include "tkbltGraphBar.h"
+#include "tkbltGrElemBar.h"
+#include "tkbltGrElemOption.h"
+#include "tkbltGrAxis.h"
+#include "tkbltGrMisc.h"
+#include "tkbltGrDef.h"
+#include "tkbltConfig.h"
+#include "tkbltGrPSOutput.h"
+#include "tkbltInt.h"
+
+using namespace Blt;
+
+#define CLAMP(x,l,h) ((x) = (((x)<(l))? (l) : ((x)>(h)) ? (h) : (x)))
+#define MIN3(a,b,c) (((a)<(b))?(((a)<(c))?(a):(c)):(((b)<(c))?(b):(c)))
+
+#define PointInRectangle(r,x0,y0) \
+ (((x0) <= (int)((r)->x + (r)->width - 1)) && ((x0) >= (int)(r)->x) && \
+ ((y0) <= (int)((r)->y + (r)->height - 1)) && ((y0) >= (int)(r)->y))
+
+// OptionSpecs
+
+static Tk_ObjCustomOption styleObjOption =
+ {
+ "style", StyleSetProc, StyleGetProc, StyleRestoreProc, StyleFreeProc,
+ (ClientData)sizeof(BarStyle)
+ };
+
+extern Tk_ObjCustomOption penObjOption;
+extern Tk_ObjCustomOption pairsObjOption;
+extern Tk_ObjCustomOption valuesObjOption;
+extern Tk_ObjCustomOption xAxisObjOption;
+extern Tk_ObjCustomOption yAxisObjOption;
+
+static Tk_OptionSpec optionSpecs[] = {
+ {TK_OPTION_CUSTOM, "-activepen", "activePen", "ActivePen",
+ "active", -1, Tk_Offset(BarElementOptions, activePenPtr),
+ TK_OPTION_NULL_OK, &penObjOption, LAYOUT},
+ {TK_OPTION_SYNONYM, "-background", NULL, NULL,
+ NULL, 0, -1, 0, (ClientData)"-color", 0},
+ {TK_OPTION_DOUBLE, "-barwidth", "barWidth", "BarWidth",
+ "0", -1, Tk_Offset(BarElementOptions, barWidth), 0, NULL, LAYOUT},
+ {TK_OPTION_SYNONYM, "-bd", NULL, NULL,
+ NULL, 0, -1, 0, (ClientData)"-borderwidth", 0},
+ {TK_OPTION_SYNONYM, "-bg", NULL, NULL,
+ NULL, 0, -1, 0, (ClientData)"-color", 0},
+ {TK_OPTION_CUSTOM, "-bindtags", "bindTags", "BindTags",
+ "all", -1, Tk_Offset(BarElementOptions, tags),
+ TK_OPTION_NULL_OK, &listObjOption, 0},
+ {TK_OPTION_PIXELS, "-borderwidth", "borderWidth", "BorderWidth",
+ STD_BORDERWIDTH, -1, Tk_Offset(BarElementOptions, builtinPen.borderWidth),
+ 0, NULL, CACHE},
+ {TK_OPTION_BORDER, "-color", "color", "color",
+ STD_NORMAL_FOREGROUND, -1, Tk_Offset(BarElementOptions, builtinPen.fill),
+ 0, NULL, CACHE},
+ {TK_OPTION_CUSTOM, "-data", "data", "Data",
+ NULL, -1, Tk_Offset(BarElementOptions, coords),
+ TK_OPTION_NULL_OK, &pairsObjOption, RESET},
+ {TK_OPTION_COLOR, "-errorbarcolor", "errorBarColor", "ErrorBarColor",
+ NULL, -1, Tk_Offset(BarElementOptions, builtinPen.errorBarColor),
+ TK_OPTION_NULL_OK, NULL, CACHE},
+ {TK_OPTION_PIXELS,"-errorbarwidth", "errorBarWidth", "ErrorBarWidth",
+ "1", -1, Tk_Offset(BarElementOptions, builtinPen.errorBarLineWidth),
+ 0, NULL, CACHE},
+ {TK_OPTION_PIXELS, "-errorbarcap", "errorBarCap", "ErrorBarCap",
+ "0", -1, Tk_Offset(BarElementOptions, builtinPen.errorBarCapWidth),
+ 0, NULL, LAYOUT},
+ {TK_OPTION_SYNONYM, "-fg", NULL, NULL,
+ NULL, 0, -1, 0, (ClientData)"-outline", 0},
+ {TK_OPTION_SYNONYM, "-fill", NULL, NULL,
+ NULL, 0, -1, 0, (ClientData)"-color", 0},
+ {TK_OPTION_SYNONYM, "-foreground", NULL, NULL,
+ NULL, 0, -1, 0, (ClientData)"-outline", 0},
+ {TK_OPTION_BOOLEAN, "-hide", "hide", "Hide",
+ "no", -1, Tk_Offset(BarElementOptions, hide), 0, NULL, LAYOUT},
+ {TK_OPTION_STRING, "-label", "label", "Label",
+ NULL, -1, Tk_Offset(BarElementOptions, label),
+ TK_OPTION_NULL_OK, NULL, LAYOUT},
+ {TK_OPTION_RELIEF, "-legendrelief", "legendRelief", "LegendRelief",
+ "flat", -1, Tk_Offset(BarElementOptions, legendRelief), 0, NULL, LAYOUT},
+ {TK_OPTION_CUSTOM, "-mapx", "mapX", "MapX",
+ "x", -1, Tk_Offset(BarElementOptions, xAxis), 0, &xAxisObjOption, RESET},
+ {TK_OPTION_CUSTOM, "-mapy", "mapY", "MapY",
+ "y", -1, Tk_Offset(BarElementOptions, yAxis), 0, &yAxisObjOption, RESET},
+ {TK_OPTION_COLOR, "-outline", "outline", "Outline",
+ NULL, -1, Tk_Offset(BarElementOptions, builtinPen.outlineColor),
+ TK_OPTION_NULL_OK, NULL, CACHE},
+ {TK_OPTION_CUSTOM, "-pen", "pen", "Pen",
+ NULL, -1, Tk_Offset(BarElementOptions, normalPenPtr),
+ TK_OPTION_NULL_OK, &penObjOption, LAYOUT},
+ {TK_OPTION_RELIEF, "-relief", "relief", "Relief",
+ "raised", -1, Tk_Offset(BarElementOptions, builtinPen.relief),
+ 0, NULL, LAYOUT},
+ {TK_OPTION_STRING_TABLE, "-showerrorbars", "showErrorBars", "ShowErrorBars",
+ "both", -1, Tk_Offset(BarElementOptions, builtinPen.errorBarShow),
+ 0, &fillObjOption, LAYOUT},
+ {TK_OPTION_STRING_TABLE, "-showvalues", "showValues", "ShowValues",
+ "none", -1, Tk_Offset(BarElementOptions, builtinPen.valueShow),
+ 0, &fillObjOption, CACHE},
+ {TK_OPTION_STRING, "-stack", "stack", "Stack",
+ NULL, -1, Tk_Offset(BarElementOptions, groupName),
+ TK_OPTION_NULL_OK, NULL, RESET},
+ {TK_OPTION_CUSTOM, "-styles", "styles", "Styles",
+ "", -1, Tk_Offset(BarElementOptions, stylePalette),
+ 0, &styleObjOption, RESET},
+ {TK_OPTION_ANCHOR, "-valueanchor", "valueAnchor", "ValueAnchor",
+ "s", -1, Tk_Offset(BarElementOptions, builtinPen.valueStyle.anchor),
+ 0, NULL, CACHE},
+ {TK_OPTION_COLOR, "-valuecolor", "valueColor", "ValueColor",
+ STD_NORMAL_FOREGROUND, -1,
+ Tk_Offset(BarElementOptions,builtinPen.valueStyle.color), 0, NULL, CACHE},
+ {TK_OPTION_FONT, "-valuefont", "valueFont", "ValueFont",
+ STD_FONT_SMALL, -1, Tk_Offset(BarElementOptions, builtinPen.valueStyle.font),
+ 0, NULL, CACHE},
+ {TK_OPTION_STRING, "-valueformat", "valueFormat", "ValueFormat",
+ "%g", -1, Tk_Offset(BarElementOptions, builtinPen.valueFormat),
+ TK_OPTION_NULL_OK, NULL, CACHE},
+ {TK_OPTION_DOUBLE, "-valuerotate", "valueRotate", "ValueRotate",
+ "0", -1, Tk_Offset(BarElementOptions, builtinPen.valueStyle.angle),
+ 0, NULL, CACHE},
+ {TK_OPTION_CUSTOM, "-weights", "weights", "Weights",
+ NULL, -1, Tk_Offset(BarElementOptions, w),
+ TK_OPTION_NULL_OK, &valuesObjOption, RESET},
+ {TK_OPTION_SYNONYM, "-x", NULL, NULL,
+ NULL, 0, -1, 0, (ClientData)"-xdata", 0},
+ {TK_OPTION_CUSTOM, "-xdata", "xData", "XData",
+ NULL, -1, Tk_Offset(BarElementOptions, coords.x),
+ TK_OPTION_NULL_OK, &valuesObjOption, RESET},
+ {TK_OPTION_CUSTOM, "-xerror", "xError", "XError",
+ NULL, -1, Tk_Offset(BarElementOptions, xError),
+ TK_OPTION_NULL_OK, &valuesObjOption, RESET},
+ {TK_OPTION_CUSTOM, "-xhigh", "xHigh", "XHigh",
+ NULL, -1, Tk_Offset(BarElementOptions, xHigh),
+ TK_OPTION_NULL_OK, &valuesObjOption, RESET},
+ {TK_OPTION_CUSTOM, "-xlow", "xLow", "XLow",
+ NULL, -1, Tk_Offset(BarElementOptions, xLow),
+ TK_OPTION_NULL_OK, &valuesObjOption, RESET},
+ {TK_OPTION_SYNONYM, "-y", NULL, NULL,
+ NULL, 0, -1, 0, (ClientData)"-ydata", 0},
+ {TK_OPTION_CUSTOM, "-ydata", "yData", "YData",
+ NULL, -1, Tk_Offset(BarElementOptions, coords.y),
+ TK_OPTION_NULL_OK, &valuesObjOption, RESET},
+ {TK_OPTION_CUSTOM, "-yerror", "yError", "YError",
+ NULL, -1, Tk_Offset(BarElementOptions, yError),
+ TK_OPTION_NULL_OK, &valuesObjOption, RESET},
+ {TK_OPTION_CUSTOM, "-yhigh", "yHigh", "YHigh",
+ NULL, -1, Tk_Offset(BarElementOptions, yHigh),
+ TK_OPTION_NULL_OK, &valuesObjOption, RESET},
+ {TK_OPTION_CUSTOM, "-ylow", "yLow", "YLow",
+ NULL, -1, Tk_Offset(BarElementOptions, yLow),
+ TK_OPTION_NULL_OK, &valuesObjOption, RESET},
+ {TK_OPTION_END, NULL, NULL, NULL, NULL, 0, -1, 0, 0, 0}
+};
+
+BarElement::BarElement(Graph* graphPtr, const char* name, Tcl_HashEntry* hPtr)
+ : Element(graphPtr, name, hPtr)
+{
+ barToData_ =NULL;
+ bars_ =NULL;
+ activeToData_ =NULL;
+ activeRects_ =NULL;
+ nBars_ =0;
+ nActive_ =0;
+
+ xeb_.segments =NULL;
+ xeb_.map =NULL;
+ xeb_.length =0;
+ yeb_.segments =NULL;
+ yeb_.map =NULL;
+ yeb_.length =0;
+
+ ops_ = (BarElementOptions*)calloc(1, sizeof(BarElementOptions));
+ BarElementOptions* ops = (BarElementOptions*)ops_;
+ ops->elemPtr = (Element*)this;
+
+ builtinPenPtr = new BarPen(graphPtr_, "builtin", &ops->builtinPen);
+ ops->builtinPenPtr = builtinPenPtr;
+
+ optionTable_ = Tk_CreateOptionTable(graphPtr->interp_, optionSpecs);
+
+ ops->stylePalette = new Chain();
+
+ // this is an option and will be freed via Tk_FreeConfigOptions
+ // By default an element's name and label are the same
+ ops->label = Tcl_Alloc(strlen(name)+1);
+ if (name)
+ strcpy((char*)ops->label,(char*)name);
+
+ Tk_InitOptions(graphPtr_->interp_, (char*)&(ops->builtinPen),
+ builtinPenPtr->optionTable(), graphPtr->tkwin_);
+}
+
+BarElement::~BarElement()
+{
+ BarElementOptions* ops = (BarElementOptions*)ops_;
+
+ delete builtinPenPtr;
+
+ reset();
+
+ if (ops->stylePalette) {
+ freeStylePalette(ops->stylePalette);
+ delete ops->stylePalette;
+ }
+}
+
+int BarElement::configure()
+{
+ BarElementOptions* ops = (BarElementOptions*)ops_;
+
+ if (builtinPenPtr->configure() != TCL_OK)
+ return TCL_ERROR;
+
+ // Point to the static normal pen if no external pens have been selected.
+ ChainLink* link = Chain_FirstLink(ops->stylePalette);
+ if (!link) {
+ link = new ChainLink(sizeof(BarStyle));
+ ops->stylePalette->linkAfter(link, NULL);
+ }
+ BarStyle* stylePtr = (BarStyle*)Chain_GetValue(link);
+ stylePtr->penPtr = NORMALPEN(ops);
+
+ return TCL_OK;
+}
+
+void BarElement::map()
+{
+ BarGraph* barGraphPtr_ = (BarGraph*)graphPtr_;
+ BarElementOptions* ops = (BarElementOptions*)ops_;
+ BarGraphOptions* gops = (BarGraphOptions*)graphPtr_->ops_;
+
+ if (!link)
+ return;
+
+ reset();
+ if (!ops->coords.x || !ops->coords.y ||
+ !ops->coords.x->nValues() || !ops->coords.y->nValues())
+ return;
+ int nPoints = NUMBEROFPOINTS(ops);
+
+ double barWidth = (ops->barWidth > 0.0) ? ops->barWidth : gops->barWidth;
+ AxisOptions* axisyops = (AxisOptions*)ops->yAxis->ops();
+ double baseline = (axisyops->logScale) ? 0.0 : gops->baseline;
+ double barOffset = barWidth * 0.5;
+
+ // Create an array of bars representing the screen coordinates of all the
+ // segments in the bar.
+ Rectangle* bars = new Rectangle[nPoints];
+ int* barToData = new int[nPoints];
+
+ double* x = ops->coords.x->values_;
+ double* y = ops->coords.y->values_;
+ int count = 0;
+
+ int ii;
+ Rectangle* rp;
+ for (rp=bars, ii=0; ii<nPoints; ii++) {
+ // Two opposite corners of the rectangle in graph coordinates
+ Point2d c1, c2;
+
+ // check Abscissa is out of range of the x-axis
+ if (((x[ii] - barWidth) > ops->xAxis->axisRange_.max) ||
+ ((x[ii] + barWidth) < ops->xAxis->axisRange_.min))
+ continue;
+
+ c1.x = x[ii] - barOffset;
+ c1.y = y[ii];
+ c2.x = c1.x + barWidth;
+ c2.y = baseline;
+
+ // If the mode is "aligned" or "stacked" we need to adjust the x or y
+ // coordinates of the two corners.
+ if ((barGraphPtr_->nBarGroups_ > 0) &&
+ ((BarGraph::BarMode)gops->barMode != BarGraph::INFRONT) &&
+ (!gops->stackAxes)) {
+
+ BarSetKey key;
+ key.value =x[ii];
+ key.xAxis =ops->xAxis;
+ key.yAxis =NULL;
+ Tcl_HashEntry* hPtr =
+ Tcl_FindHashEntry(&barGraphPtr_->setTable_, (char*)&key);
+
+ if (hPtr) {
+ Tcl_HashTable *tablePtr = (Tcl_HashTable*)Tcl_GetHashValue(hPtr);
+ const char *name = (ops->groupName) ? ops->groupName:ops->yAxis->name_;
+ Tcl_HashEntry* hPtr2 = Tcl_FindHashEntry(tablePtr, name);
+ if (hPtr2) {
+ BarGroup* groupPtr = (BarGroup*)Tcl_GetHashValue(hPtr2);
+ double slice = barWidth / (double)barGraphPtr_->maxBarSetSize_;
+ double offset = (slice * groupPtr->index);
+ if (barGraphPtr_->maxBarSetSize_ > 1) {
+ offset += slice * 0.05;
+ slice *= 0.90;
+ }
+
+ switch ((BarGraph::BarMode)gops->barMode) {
+ case BarGraph::STACKED:
+ groupPtr->count++;
+ c2.y = groupPtr->lastY;
+ c1.y += c2.y;
+ groupPtr->lastY = c1.y;
+ c1.x += offset;
+ c2.x = c1.x + slice;
+ break;
+
+ case BarGraph::ALIGNED:
+ slice /= groupPtr->nSegments;
+ c1.x += offset + (slice * groupPtr->count);
+ c2.x = c1.x + slice;
+ groupPtr->count++;
+ break;
+
+ case BarGraph::OVERLAP:
+ {
+ slice /= (groupPtr->nSegments + 1);
+ double width = slice + slice;
+ groupPtr->count++;
+ c1.x += offset +
+ (slice * (groupPtr->nSegments - groupPtr->count));
+ c2.x = c1.x + width;
+ }
+ break;
+
+ case BarGraph::INFRONT:
+ break;
+ }
+ }
+ }
+ }
+
+ int invertBar = 0;
+ if (c1.y < c2.y) {
+ // Handle negative bar values by swapping ordinates
+ double temp = c1.y;
+ c1.y = c2.y;
+ c2.y = temp;
+ invertBar = 1;
+ }
+
+ // Get the two corners of the bar segment and compute the rectangle
+ double ybot = c2.y;
+ c1 = graphPtr_->map2D(c1.x, c1.y, ops->xAxis, ops->yAxis);
+ c2 = graphPtr_->map2D(c2.x, c2.y, ops->xAxis, ops->yAxis);
+ if ((ybot == 0.0) && (axisyops->logScale))
+ c2.y = graphPtr_->bottom_;
+
+ if (c2.y < c1.y) {
+ double t = c1.y;
+ c1.y = c2.y;
+ c2.y = t;
+ }
+
+ if (c2.x < c1.x) {
+ double t = c1.x;
+ c1.x = c2.x;
+ c2.x = t;
+ }
+
+ if ((c1.x > graphPtr_->right_) || (c2.x < graphPtr_->left_) ||
+ (c1.y > graphPtr_->bottom_) || (c2.y < graphPtr_->top_))
+ continue;
+
+ // Bound the bars horizontally by the width of the graph window
+ // Bound the bars vertically by the position of the axis.
+ double right =0;
+ double left =0;
+ double top =0;
+ double bottom =0;
+ if (gops->stackAxes) {
+ top = ops->yAxis->screenMin_;
+ bottom = ops->yAxis->screenMin_ + ops->yAxis->screenRange_;
+ left = graphPtr_->left_;
+ right = graphPtr_->right_;
+ }
+ else {
+ bottom = right = 10000;
+ // Shouldn't really have a call to Tk_Width or Tk_Height in
+ // mapping routine. We only want to clamp the bar segment to the
+ // size of the window if we're actually mapped onscreen
+ if (Tk_Height(graphPtr_->tkwin_) > 1)
+ bottom = Tk_Height(graphPtr_->tkwin_);
+ if (Tk_Width(graphPtr_->tkwin_) > 1)
+ right = Tk_Width(graphPtr_->tkwin_);
+ }
+
+ CLAMP(c1.y, top, bottom);
+ CLAMP(c2.y, top, bottom);
+ CLAMP(c1.x, left, right);
+ CLAMP(c2.x, left, right);
+ double dx = fabs(c1.x - c2.x);
+ double dy = fabs(c1.y - c2.y);
+ if ((dx == 0) || (dy == 0))
+ continue;
+
+ int height = (int)dy;
+ int width = (int)dx;
+ if (invertBar)
+ rp->y = (int)MIN(c1.y, c2.y);
+ else
+ rp->y = (int)(MAX(c1.y, c2.y)) - height;
+
+ rp->x = (int)MIN(c1.x, c2.x);
+
+ rp->width = width + 1;
+ rp->width |= 0x1;
+ if (rp->width < 1)
+ rp->width = 1;
+
+ rp->height = height + 1;
+ if (rp->height < 1)
+ rp->height = 1;
+
+ // Save the data index corresponding to the rectangle
+ barToData[count] = ii;
+ count++;
+ rp++;
+ }
+ nBars_ = count;
+ bars_ = bars;
+ barToData_ = barToData;
+ if (nActiveIndices_ > 0)
+ mapActive();
+
+ int size = 20;
+ if (count > 0)
+ size = bars->width;
+
+ // Set the symbol size of all the pen styles
+ for (ChainLink* link = Chain_FirstLink(ops->stylePalette); link;
+ link = Chain_NextLink(link)) {
+ BarStyle *stylePtr = (BarStyle*)Chain_GetValue(link);
+ BarPen* penPtr = stylePtr->penPtr;
+ BarPenOptions* pops = (BarPenOptions*)penPtr->ops();
+ stylePtr->symbolSize = size;
+ stylePtr->errorBarCapWidth = pops->errorBarCapWidth;
+ }
+
+ BarStyle** dataToStyle = (BarStyle**)StyleMap();
+ if (((ops->yHigh && ops->yHigh->nValues() > 0) &&
+ (ops->yLow && ops->yLow->nValues() > 0)) ||
+ ((ops->xHigh && ops->xHigh->nValues() > 0) &&
+ (ops->xLow && ops->xLow->nValues() > 0)) ||
+ (ops->xError && ops->xError->nValues() > 0) ||
+ (ops->yError && ops->yError->nValues() > 0)) {
+ mapErrorBars(dataToStyle);
+ }
+
+ mergePens(dataToStyle);
+ delete [] dataToStyle;
+}
+
+void BarElement::extents(Region2d *regPtr)
+{
+ BarGraph* barGraphPtr_ = (BarGraph*)graphPtr_;
+ BarElementOptions* ops = (BarElementOptions*)ops_;
+ BarGraphOptions* gops = (BarGraphOptions*)graphPtr_->ops_;
+
+ regPtr->top = regPtr->left = DBL_MAX;
+ regPtr->bottom = regPtr->right = -DBL_MAX;
+
+ if (!ops->coords.x || !ops->coords.y ||
+ !ops->coords.x->nValues() || !ops->coords.y->nValues())
+ return;
+
+ int nPoints = NUMBEROFPOINTS(ops);
+
+ double middle = 0.5;
+ regPtr->left = ops->coords.x->min() - middle;
+ regPtr->right = ops->coords.x->max() + middle;
+
+ regPtr->top = ops->coords.y->min();
+ regPtr->bottom = ops->coords.y->max();
+ if (regPtr->bottom < gops->baseline)
+ regPtr->bottom = gops->baseline;
+
+ // Handle stacked bar elements specially.
+ // If element is stacked, the sum of its ordinates may be outside the
+ // minimum/maximum limits of the element's data points.
+ if (((BarGraph::BarMode)gops->barMode == BarGraph::STACKED) &&
+ (barGraphPtr_->nBarGroups_ > 0))
+ checkStacks(ops->xAxis, ops->yAxis, &regPtr->top, &regPtr->bottom);
+
+ // Warning: You get what you deserve if the x-axis is logScale
+ AxisOptions* axisxops = (AxisOptions*)ops->xAxis->ops();
+ AxisOptions* axisyops = (AxisOptions*)ops->yAxis->ops();
+ if (axisxops->logScale)
+ regPtr->left = FindElemValuesMinimum(ops->coords.x, DBL_MIN) + middle;
+
+ // Fix y-min limits for barchart
+ if (axisyops->logScale) {
+ if ((regPtr->top <= 0.0) || (regPtr->top > 1.0))
+ regPtr->top = 1.0;
+ }
+ else {
+ if (regPtr->top > 0.0)
+ regPtr->top = 0.0;
+ }
+
+ // Correct the extents for error bars if they exist
+ if (ops->xError && (ops->xError->nValues() > 0)) {
+ nPoints = MIN(ops->xError->nValues(), nPoints);
+ for (int ii=0; ii<nPoints; ii++) {
+ double x = ops->coords.x->values_[ii] + ops->xError->values_[ii];
+ if (x > regPtr->right)
+ regPtr->right = x;
+
+ x = ops->coords.x->values_[ii] - ops->xError->values_[ii];
+ if (axisxops->logScale) {
+ // Mirror negative values, instead of ignoring them
+ if (x < 0.0)
+ x = -x;
+
+ if ((x > DBL_MIN) && (x < regPtr->left))
+ regPtr->left = x;
+
+ }
+ else if (x < regPtr->left)
+ regPtr->left = x;
+ }
+ }
+ else {
+ if ((ops->xHigh) &&
+ (ops->xHigh->nValues() > 0) &&
+ (ops->xHigh->max() > regPtr->right))
+ regPtr->right = ops->xHigh->max();
+
+ if (ops->xLow && (ops->xLow->nValues() > 0)) {
+ double left;
+ if ((ops->xLow->min() <= 0.0) && (axisxops->logScale))
+ left = FindElemValuesMinimum(ops->xLow, DBL_MIN);
+ else
+ left = ops->xLow->min();
+
+ if (left < regPtr->left)
+ regPtr->left = left;
+ }
+ }
+
+ if (ops->yError && (ops->yError->nValues() > 0)) {
+ nPoints = MIN(ops->yError->nValues(), nPoints);
+
+ for (int ii=0; ii<nPoints; ii++) {
+ double y = ops->coords.y->values_[ii] + ops->yError->values_[ii];
+ if (y > regPtr->bottom)
+ regPtr->bottom = y;
+
+ y = ops->coords.y->values_[ii] - ops->yError->values_[ii];
+ if (axisyops->logScale) {
+ // Mirror negative values, instead of ignoring them
+ if (y < 0.0)
+ y = -y;
+
+ if ((y > DBL_MIN) && (y < regPtr->left))
+ regPtr->top = y;
+
+ }
+ else if (y < regPtr->top)
+ regPtr->top = y;
+ }
+ }
+ else {
+ if ((ops->yHigh) &&
+ (ops->yHigh->nValues() > 0) &&
+ (ops->yHigh->max() > regPtr->bottom))
+ regPtr->bottom = ops->yHigh->max();
+
+ if (ops->yLow && ops->yLow->nValues() > 0) {
+ double top;
+ if ((ops->yLow->min() <= 0.0) &&
+ (axisyops->logScale))
+ top = FindElemValuesMinimum(ops->yLow, DBL_MIN);
+ else
+ top = ops->yLow->min();
+
+ if (top < regPtr->top)
+ regPtr->top = top;
+ }
+ }
+}
+
+void BarElement::closest()
+{
+ BarElementOptions* ops = (BarElementOptions*)ops_;
+ BarGraphOptions* gops = (BarGraphOptions*)graphPtr_->ops_;
+
+ ClosestSearch* searchPtr = &gops->search;
+ double minDist = searchPtr->dist;
+ int imin = 0;
+
+ int ii;
+ Rectangle* bp;
+ for (bp=bars_, ii=0; ii<nBars_; ii++, bp++) {
+ if (PointInRectangle(bp, searchPtr->x, searchPtr->y)) {
+ imin = barToData_[ii];
+ minDist = 0.0;
+ break;
+ }
+ double left = bp->x;
+ double top = bp->y;
+ double right = (double)(bp->x + bp->width);
+ double bottom = (double)(bp->y + bp->height);
+
+ Point2d outline[5];
+ outline[4].x = outline[3].x = outline[0].x = left;
+ outline[4].y = outline[1].y = outline[0].y = top;
+ outline[2].x = outline[1].x = right;
+ outline[3].y = outline[2].y = bottom;
+
+ Point2d *pp, *pend;
+ for (pp=outline, pend=outline+4; pp<pend; pp++) {
+ Point2d t = getProjection(searchPtr->x, searchPtr->y, pp, pp + 1);
+ if (t.x > right)
+ t.x = right;
+ else if (t.x < left)
+ t.x = left;
+
+ if (t.y > bottom)
+ t.y = bottom;
+ else if (t.y < top)
+ t.y = top;
+
+ double dist = hypot((t.x - searchPtr->x), (t.y - searchPtr->y));
+ if (dist < minDist) {
+ minDist = dist;
+ imin = barToData_[ii];
+ }
+ }
+ }
+ if (minDist < searchPtr->dist) {
+ searchPtr->elemPtr = (Element*)this;
+ searchPtr->dist = minDist;
+ searchPtr->index = imin;
+ searchPtr->point.x =
+ ops->coords.x ? (double)ops->coords.x->values_[imin] : 0;
+ searchPtr->point.y =
+ ops->coords.y ? (double)ops->coords.y->values_[imin] : 0;
+ }
+}
+
+void BarElement::draw(Drawable drawable)
+{
+ BarElementOptions* ops = (BarElementOptions*)ops_;
+
+ if (ops->hide)
+ return;
+
+ int count = 0;
+ for (ChainLink* link = Chain_FirstLink(ops->stylePalette); link;
+ link = Chain_NextLink(link)) {
+
+ BarStyle* stylePtr = (BarStyle*)Chain_GetValue(link);
+ BarPen* penPtr = (BarPen*)stylePtr->penPtr;
+ BarPenOptions* pops = (BarPenOptions*)penPtr->ops();
+
+ if (stylePtr->nBars > 0)
+ drawSegments(drawable, penPtr, stylePtr->bars, stylePtr->nBars);
+
+ if ((stylePtr->xeb.length > 0) && (pops->errorBarShow & SHOW_X))
+ graphPtr_->drawSegments(drawable, penPtr->errorBarGC_,
+ stylePtr->xeb.segments, stylePtr->xeb.length);
+
+ if ((stylePtr->yeb.length > 0) && (pops->errorBarShow & SHOW_Y))
+ graphPtr_->drawSegments(drawable, penPtr->errorBarGC_,
+ stylePtr->yeb.segments, stylePtr->yeb.length);
+
+ if (pops->valueShow != SHOW_NONE)
+ drawValues(drawable, penPtr, stylePtr->bars, stylePtr->nBars,
+ barToData_ + count);
+
+ count += stylePtr->nBars;
+ }
+}
+
+void BarElement::drawActive(Drawable drawable)
+{
+ BarElementOptions* ops = (BarElementOptions*)ops_;
+
+ if (ops->hide || !active_)
+ return;
+
+ BarPen* penPtr = (BarPen*)ops->activePenPtr;
+ if (!penPtr)
+ return;
+ BarPenOptions* pops = (BarPenOptions*)penPtr->ops();
+
+ if (nActiveIndices_ > 0) {
+ mapActive();
+
+ drawSegments(drawable, penPtr, activeRects_, nActive_);
+ if (pops->valueShow != SHOW_NONE)
+ drawValues(drawable, penPtr, activeRects_, nActive_, activeToData_);
+ }
+ else if (nActiveIndices_ < 0) {
+ drawSegments(drawable, penPtr, bars_, nBars_);
+ if (pops->valueShow != SHOW_NONE)
+ drawValues(drawable, penPtr, bars_, nBars_, barToData_);
+ }
+}
+
+void BarElement::drawSymbol(Drawable drawable, int x, int y, int size)
+{
+ BarElementOptions* ops = (BarElementOptions*)ops_;
+
+ BarPen* penPtr = NORMALPEN(ops);
+ BarPenOptions* pops = (BarPenOptions*)penPtr->ops();
+
+ int radius = (size / 2);
+ size--;
+
+ x -= radius;
+ y -= radius;
+
+ Tk_Fill3DRectangle(graphPtr_->tkwin_, drawable,
+ pops->fill, x, y, size, size,
+ pops->borderWidth, pops->relief);
+
+ if (pops->outlineColor)
+ XDrawRectangle(graphPtr_->display_, drawable, penPtr->outlineGC_,
+ x, y, size, size);
+}
+
+void BarElement::print(PSOutput* psPtr)
+{
+ BarElementOptions* ops = (BarElementOptions*)ops_;
+
+ if (ops->hide)
+ return;
+
+ psPtr->format("\n%% Element \"%s\"\n\n", name_);
+
+ int count = 0;
+ for (ChainLink* link = Chain_FirstLink(ops->stylePalette); link;
+ link = Chain_NextLink(link)) {
+
+ BarStyle *stylePtr = (BarStyle*)Chain_GetValue(link);
+ BarPen* penPtr = (BarPen*)stylePtr->penPtr;
+ BarPenOptions* pops = (BarPenOptions*)penPtr->ops();
+
+ if (stylePtr->nBars > 0)
+ printSegments(psPtr, penPtr, stylePtr->bars, stylePtr->nBars);
+
+ XColor* colorPtr = pops->errorBarColor;
+ if (!colorPtr)
+ colorPtr = pops->outlineColor;
+ if (!colorPtr)
+ colorPtr = Tk_3DBorderColor(pops->fill);
+
+ if ((stylePtr->xeb.length > 0) && (pops->errorBarShow & SHOW_X)) {
+ psPtr->setLineAttributes(colorPtr, pops->errorBarLineWidth,
+ NULL, CapButt, JoinMiter);
+ psPtr->printSegments(stylePtr->xeb.segments, stylePtr->xeb.length);
+ }
+
+ if ((stylePtr->yeb.length > 0) && (pops->errorBarShow & SHOW_Y)) {
+ psPtr->setLineAttributes(colorPtr, pops->errorBarLineWidth,
+ NULL, CapButt, JoinMiter);
+ psPtr->printSegments(stylePtr->yeb.segments, stylePtr->yeb.length);
+ }
+
+ if (pops->valueShow != SHOW_NONE)
+ printValues(psPtr, penPtr, stylePtr->bars, stylePtr->nBars,
+ barToData_ + count);
+
+ count += stylePtr->nBars;
+ }
+}
+
+void BarElement::printActive(PSOutput* psPtr)
+{
+ BarElementOptions* ops = (BarElementOptions*)ops_;
+
+ if (ops->hide || !active_)
+ return;
+
+ BarPen* penPtr = (BarPen*)ops->activePenPtr;
+ if (!penPtr)
+ return;
+ BarPenOptions* pops = (BarPenOptions*)penPtr->ops();
+
+ psPtr->format("\n%% Active Element \"%s\"\n\n", name_);
+
+ if (nActiveIndices_ > 0) {
+ mapActive();
+
+ printSegments(psPtr, penPtr, activeRects_, nActive_);
+ if (pops->valueShow != SHOW_NONE)
+ printValues(psPtr, penPtr, activeRects_, nActive_,activeToData_);
+ }
+ else if (nActiveIndices_ < 0) {
+ printSegments(psPtr, penPtr, bars_, nBars_);
+ if (pops->valueShow != SHOW_NONE)
+ printValues(psPtr, penPtr, bars_, nBars_, barToData_);
+ }
+}
+
+void BarElement::printSymbol(PSOutput* psPtr, double x, double y, int size)
+{
+ BarElementOptions* ops = (BarElementOptions*)ops_;
+
+ BarPen* penPtr = NORMALPEN(ops);
+ BarPenOptions* pops = (BarPenOptions*)penPtr->ops();
+
+ x -= size/2.;
+ y -= size/2.;
+
+ psPtr->fill3DRectangle(pops->fill, x, y, size, size,
+ pops->borderWidth, pops->relief);
+
+ if (pops->outlineColor) {
+ psPtr->setForeground(pops->outlineColor);
+ psPtr->printRectangle(x, y, size, size);
+ }
+}
+
+// Support
+
+void BarElement::ResetStylePalette(Chain* stylePalette)
+{
+ for (ChainLink* link = Chain_FirstLink(stylePalette); link;
+ link = Chain_NextLink(link)) {
+ BarStyle *stylePtr = (BarStyle*)Chain_GetValue(link);
+ stylePtr->xeb.length = 0;
+ stylePtr->yeb.length = 0;
+ stylePtr->nBars = 0;
+ }
+}
+
+void BarElement::checkStacks(Axis* xAxis, Axis* yAxis,
+ double* minPtr, double* maxPtr)
+{
+ BarGraph* barGraphPtr_ = (BarGraph*)graphPtr_;
+ BarGraphOptions* gops = (BarGraphOptions*)graphPtr_->ops_;
+ if (((BarGraph::BarMode)gops->barMode != BarGraph::STACKED) ||
+ barGraphPtr_->nBarGroups_ == 0)
+ return;
+
+ for (BarGroup *gp = barGraphPtr_->barGroups_,
+ *gend = gp + barGraphPtr_->nBarGroups_; gp < gend; gp++) {
+ if ((gp->xAxis == xAxis) && (gp->yAxis == yAxis)) {
+
+ // Check if any of the y-values (because of stacking) are greater
+ // than the current limits of the graph.
+ if (gp->sum < 0.0) {
+ if (*minPtr > gp->sum)
+ *minPtr = gp->sum;
+ }
+ else {
+ if (*maxPtr < gp->sum)
+ *maxPtr = gp->sum;
+ }
+ }
+ }
+}
+
+void BarElement::mergePens(BarStyle** dataToStyle)
+{
+ BarElementOptions* ops = (BarElementOptions*)ops_;
+
+ if (Chain_GetLength(ops->stylePalette) < 2) {
+ ChainLink* link = Chain_FirstLink(ops->stylePalette);
+ BarStyle *stylePtr = (BarStyle*)Chain_GetValue(link);
+ stylePtr->nBars = nBars_;
+ stylePtr->bars = bars_;
+ stylePtr->symbolSize = bars_->width / 2;
+ stylePtr->xeb.length = xeb_.length;
+ stylePtr->xeb.segments = xeb_.segments;
+ stylePtr->yeb.length = yeb_.length;
+ stylePtr->yeb.segments = yeb_.segments;
+ return;
+ }
+
+ // We have more than one style. Group bar segments of like pen styles together
+ if (nBars_ > 0) {
+ Rectangle* bars = new Rectangle[nBars_];
+ int* barToData = new int[nBars_];
+ Rectangle* bp = bars;
+ int* ip = barToData;
+ for (ChainLink* link = Chain_FirstLink(ops->stylePalette); link;
+ link = Chain_NextLink(link)) {
+ BarStyle *stylePtr = (BarStyle*)Chain_GetValue(link);
+ stylePtr->symbolSize = bp->width / 2;
+ stylePtr->bars = bp;
+ for (int ii=0; ii<nBars_; ii++) {
+ int iData = barToData[ii];
+ if (dataToStyle[iData] == stylePtr) {
+ *bp++ = bars[ii];
+ *ip++ = iData;
+ }
+ }
+ stylePtr->nBars = bp - stylePtr->bars;
+ }
+ delete [] bars_;
+ bars_ = bars;
+ delete [] barToData_;
+ barToData_ = barToData;
+ }
+
+ if (xeb_.length > 0) {
+ Segment2d* bars = new Segment2d[xeb_.length];
+ Segment2d *sp = bars;
+ int* map = new int[xeb_.length];
+ int* ip = map;
+ for (ChainLink* link = Chain_FirstLink(ops->stylePalette); link;
+ link = Chain_NextLink(link)) {
+ BarStyle *stylePtr = (BarStyle*)Chain_GetValue(link);
+ stylePtr->xeb.segments = sp;
+ for (int ii=0; ii<xeb_.length; ii++) {
+ int iData = xeb_.map[ii];
+ if (dataToStyle[iData] == stylePtr) {
+ *sp++ = xeb_.segments[ii];
+ *ip++ = iData;
+ }
+ }
+ stylePtr->xeb.length = sp - stylePtr->xeb.segments;
+ }
+ delete [] xeb_.segments;
+ xeb_.segments = bars;
+ delete [] xeb_.map;
+ xeb_.map = map;
+ }
+
+ if (yeb_.length > 0) {
+ Segment2d* bars = new Segment2d[yeb_.length];
+ Segment2d* sp = bars;
+ int* map = new int[yeb_.length];
+ int* ip = map;
+ for (ChainLink* link = Chain_FirstLink(ops->stylePalette); link;
+ link = Chain_NextLink(link)) {
+ BarStyle *stylePtr = (BarStyle*)Chain_GetValue(link);
+ stylePtr->yeb.segments = sp;
+ for (int ii=0; ii<yeb_.length; ii++) {
+ int iData = yeb_.map[ii];
+ if (dataToStyle[iData] == stylePtr) {
+ *sp++ = yeb_.segments[ii];
+ *ip++ = iData;
+ }
+ }
+ stylePtr->yeb.length = sp - stylePtr->yeb.segments;
+ }
+ delete [] yeb_.segments;
+ yeb_.segments = bars;
+ delete [] yeb_.map;
+ yeb_.map = map;
+ }
+}
+
+void BarElement::mapActive()
+{
+ delete [] activeRects_;
+ activeRects_ = NULL;
+
+ delete [] activeToData_;
+ activeToData_ = NULL;
+
+ nActive_ = 0;
+
+ if (nActiveIndices_ > 0) {
+ Rectangle* activeRects = new Rectangle[nActiveIndices_];
+ int* activeToData = new int[nActiveIndices_];
+ int count = 0;
+ for (int ii=0; ii<nBars_; ii++) {
+ for (int *ip = activeIndices_, *iend = ip + nActiveIndices_;
+ ip < iend; ip++) {
+ if (barToData_[ii] == *ip) {
+ activeRects[count] = bars_[ii];
+ activeToData[count] = ii;
+ count++;
+ }
+ }
+ }
+ nActive_ = count;
+ activeRects_ = activeRects;
+ activeToData_ = activeToData;
+ }
+}
+
+void BarElement::reset()
+{
+ BarElementOptions* ops = (BarElementOptions*)ops_;
+
+ ResetStylePalette(ops->stylePalette);
+
+ delete [] activeRects_;
+ activeRects_ = NULL;
+ delete [] activeToData_;
+ activeToData_ = NULL;
+
+ delete [] xeb_.segments;
+ xeb_.segments = NULL;
+ delete [] xeb_.map;
+ xeb_.map = NULL;
+ xeb_.length = 0;
+
+ delete [] yeb_.segments;
+ yeb_.segments = NULL;
+ delete [] yeb_.map;
+ yeb_.map = NULL;
+ yeb_.length = 0;
+
+ delete [] bars_;
+ bars_ = NULL;
+ delete [] barToData_;
+ barToData_ = NULL;
+
+ nActive_ = 0;
+ nBars_ = 0;
+}
+
+void BarElement::mapErrorBars(BarStyle **dataToStyle)
+{
+ BarElementOptions* ops = (BarElementOptions*)ops_;
+
+ Region2d reg;
+ graphPtr_->extents(&reg);
+
+ int nPoints = NUMBEROFPOINTS(ops);
+ int nn =0;
+ if (ops->coords.x && ops->coords.y) {
+ if (ops->xError && (ops->xError->nValues() > 0))
+ nn = MIN(ops->xError->nValues(), nPoints);
+ else
+ if (ops->xHigh && ops->xLow)
+ nn = MIN3(ops->xHigh->nValues(), ops->xLow->nValues(), nPoints);
+ }
+
+ if (nn) {
+ Segment2d* bars = new Segment2d[nn * 3];
+ Segment2d* segPtr = bars;
+ int* map = new int[nn * 3];
+ int* indexPtr = map;
+
+ for (int ii=0; ii<nn; ii++) {
+ double x = ops->coords.x->values_[ii];
+ double y = ops->coords.y->values_[ii];
+ BarStyle* stylePtr = dataToStyle[ii];
+
+ if ((isfinite(x)) && (isfinite(y))) {
+ double high, low;
+ if (ops->xError->nValues() > 0) {
+ high = x + ops->xError->values_[ii];
+ low = x - ops->xError->values_[ii];
+ }
+ else {
+ high = ops->xHigh ? ops->xHigh->values_[ii] : 0;
+ low = ops->xLow ? ops->xLow->values_[ii] : 0;
+ }
+ if ((isfinite(high)) && (isfinite(low))) {
+ Point2d p = graphPtr_->map2D(high, y, ops->xAxis, ops->yAxis);
+ Point2d q = graphPtr_->map2D(low, y, ops->xAxis, ops->yAxis);
+ segPtr->p = p;
+ segPtr->q = q;
+ if (lineRectClip(&reg, &segPtr->p, &segPtr->q)) {
+ segPtr++;
+ *indexPtr++ = ii;
+ }
+ // Left cap
+ segPtr->p.x = p.x;
+ segPtr->q.x = p.x;
+ segPtr->p.y = p.y - stylePtr->errorBarCapWidth;
+ segPtr->q.y = p.y + stylePtr->errorBarCapWidth;
+ if (lineRectClip(&reg, &segPtr->p, &segPtr->q)) {
+ segPtr++;
+ *indexPtr++ = ii;
+ }
+ // Right cap
+ segPtr->p.x = q.x;
+ segPtr->q.x = q.x;
+ segPtr->p.y = q.y - stylePtr->errorBarCapWidth;
+ segPtr->q.y = q.y + stylePtr->errorBarCapWidth;
+ if (lineRectClip(&reg, &segPtr->p, &segPtr->q)) {
+ segPtr++;
+ *indexPtr++ = ii;
+ }
+ }
+ }
+ }
+ xeb_.segments = bars;
+ xeb_.length = segPtr - bars;
+ xeb_.map = map;
+ }
+
+ nn =0;
+ if (ops->coords.x && ops->coords.y) {
+ if (ops->yError && (ops->yError->nValues() > 0))
+ nn = MIN(ops->yError->nValues(), nPoints);
+ else
+ if (ops->yHigh && ops->yLow)
+ nn = MIN3(ops->yHigh->nValues(), ops->yLow->nValues(), nPoints);
+ }
+
+ if (nn) {
+ Segment2d* bars = new Segment2d[nn * 3];
+ Segment2d* segPtr = bars;
+ int* map = new int[nn * 3];
+ int* indexPtr = map;
+
+ for (int ii=0; ii<nn; ii++) {
+ double x = ops->coords.x->values_[ii];
+ double y = ops->coords.y->values_[ii];
+ BarStyle *stylePtr = dataToStyle[ii];
+
+ if ((isfinite(x)) && (isfinite(y))) {
+ double high, low;
+ if (ops->yError->nValues() > 0) {
+ high = y + ops->yError->values_[ii];
+ low = y - ops->yError->values_[ii];
+ }
+ else {
+ high = ops->yHigh->values_[ii];
+ low = ops->yLow->values_[ii];
+ }
+ if ((isfinite(high)) && (isfinite(low))) {
+ Point2d p = graphPtr_->map2D(x, high, ops->xAxis, ops->yAxis);
+ Point2d q = graphPtr_->map2D(x, low, ops->xAxis, ops->yAxis);
+ segPtr->p = p;
+ segPtr->q = q;
+ if (lineRectClip(&reg, &segPtr->p, &segPtr->q)) {
+ segPtr++;
+ *indexPtr++ = ii;
+ }
+ // Top cap
+ segPtr->p.y = p.y;
+ segPtr->q.y = p.y;
+ segPtr->p.x = p.x - stylePtr->errorBarCapWidth;
+ segPtr->q.x = p.x + stylePtr->errorBarCapWidth;
+ if (lineRectClip(&reg, &segPtr->p, &segPtr->q)) {
+ segPtr++;
+ *indexPtr++ = ii;
+ }
+ // Bottom cap
+ segPtr->p.y = q.y;
+ segPtr->q.y = q.y;
+ segPtr->p.x = q.x - stylePtr->errorBarCapWidth;
+ segPtr->q.x = q.x + stylePtr->errorBarCapWidth;
+ if (lineRectClip(&reg, &segPtr->p, &segPtr->q)) {
+ segPtr++;
+ *indexPtr++ = ii;
+ }
+ }
+ }
+ }
+ yeb_.segments = bars;
+ yeb_.length = segPtr - bars;
+ yeb_.map = map;
+ }
+}
+
+void BarElement::drawSegments(Drawable drawable, BarPen* penPtr,
+ Rectangle *bars, int nBars)
+{
+ BarPenOptions* pops = (BarPenOptions*)penPtr->ops();
+ for (Rectangle *rp = bars, *rend = rp + nBars; rp < rend; rp++) {
+ if ((rp->width < 1) || (rp->height < 1))
+ continue;
+
+ Tk_Fill3DRectangle(graphPtr_->tkwin_, drawable,
+ pops->fill, rp->x, rp->y, rp->width, rp->height,
+ pops->borderWidth, pops->relief);
+
+ if (pops->outlineColor)
+ XDrawRectangle(graphPtr_->display_, drawable, penPtr->outlineGC_,
+ rp->x, rp->y, rp->width, rp->height);
+ }
+}
+
+void BarElement::drawValues(Drawable drawable, BarPen* penPtr,
+ Rectangle *bars, int nBars, int *barToData)
+{
+ BarElementOptions* ops = (BarElementOptions*)ops_;
+ BarPenOptions* pops = (BarPenOptions*)penPtr->ops();
+ BarGraphOptions* gops = (BarGraphOptions*)graphPtr_->ops_;
+
+ const char *fmt = pops->valueFormat;
+ if (!fmt)
+ fmt = "%g";
+ TextStyle ts(graphPtr_, &pops->valueStyle);
+
+ int count = 0;
+ for (Rectangle *rp = bars, *rend = rp + nBars; rp < rend; rp++) {
+ Point2d anchorPos;
+ char string[TCL_DOUBLE_SPACE * 2 + 2];
+
+ double x = ops->coords.x->values_[barToData[count]];
+ double y = ops->coords.y->values_[barToData[count]];
+
+ count++;
+ if (pops->valueShow == SHOW_X)
+ snprintf(string, TCL_DOUBLE_SPACE, fmt, x);
+ else if (pops->valueShow == SHOW_Y)
+ snprintf(string, TCL_DOUBLE_SPACE, fmt, y);
+ else if (pops->valueShow == SHOW_BOTH) {
+ snprintf(string, TCL_DOUBLE_SPACE, fmt, x);
+ strcat(string, ",");
+ snprintf(string + strlen(string), TCL_DOUBLE_SPACE, fmt, y);
+ }
+
+ if (gops->inverted) {
+ anchorPos.y = rp->y + rp->height * 0.5;
+ anchorPos.x = rp->x + rp->width;
+ if (x < gops->baseline)
+ anchorPos.x -= rp->width;
+ }
+ else {
+ anchorPos.x = rp->x + rp->width * 0.5;
+ anchorPos.y = rp->y;
+ if (y < gops->baseline)
+ anchorPos.y += rp->height;
+ }
+
+ ts.drawText(drawable, string, anchorPos.x, anchorPos.y);
+ }
+}
+
+void BarElement::printSegments(PSOutput* psPtr, BarPen* penPtr,
+ Rectangle *bars, int nBars)
+{
+ BarPenOptions* pops = (BarPenOptions*)penPtr->ops();
+ for (Rectangle *rp = bars, *rend = rp + nBars; rp < rend; rp++) {
+ if ((rp->width < 1) || (rp->height < 1))
+ continue;
+
+ psPtr->fill3DRectangle(pops->fill, (double)rp->x, (double)rp->y,
+ (int)rp->width, (int)rp->height,
+ pops->borderWidth, pops->relief);
+
+ if (pops->outlineColor) {
+ psPtr->setForeground(pops->outlineColor);
+ psPtr->printRectangle((double)rp->x, (double)rp->y,
+ (int)rp->width, (int)rp->height);
+ }
+ }
+}
+
+void BarElement::printValues(PSOutput* psPtr, BarPen* penPtr,
+ Rectangle *bars, int nBars, int *barToData)
+{
+ BarPenOptions* pops = (BarPenOptions*)penPtr->ops();
+ BarElementOptions* ops = (BarElementOptions*)ops_;
+ BarGraphOptions* gops = (BarGraphOptions*)graphPtr_->ops_;
+
+ int count = 0;
+ const char* fmt = pops->valueFormat;
+ if (!fmt)
+ fmt = "%g";
+ TextStyle ts(graphPtr_, &pops->valueStyle);
+
+ for (Rectangle *rp = bars, *rend = rp + nBars; rp < rend; rp++) {
+ double x = ops->coords.x->values_[barToData[count]];
+ double y = ops->coords.y->values_[barToData[count]];
+
+ count++;
+ char string[TCL_DOUBLE_SPACE * 2 + 2];
+ if (pops->valueShow == SHOW_X)
+ snprintf(string, TCL_DOUBLE_SPACE, fmt, x);
+ else if (pops->valueShow == SHOW_Y)
+ snprintf(string, TCL_DOUBLE_SPACE, fmt, y);
+ else if (pops->valueShow == SHOW_BOTH) {
+ snprintf(string, TCL_DOUBLE_SPACE, fmt, x);
+ strcat(string, ",");
+ snprintf(string + strlen(string), TCL_DOUBLE_SPACE, fmt, y);
+ }
+
+ Point2d anchorPos;
+ if (gops->inverted) {
+ anchorPos.y = rp->y + rp->height * 0.5;
+ anchorPos.x = rp->x + rp->width;
+ if (x < gops->baseline)
+ anchorPos.x -= rp->width;
+ }
+ else {
+ anchorPos.x = rp->x + rp->width * 0.5;
+ anchorPos.y = rp->y;
+ if (y < gops->baseline)
+ anchorPos.y += rp->height;
+ }
+
+ ts.printText(psPtr, string, anchorPos.x, anchorPos.y);
+ }
+}
+