summaryrefslogtreecommitdiffstats
path: root/tkblt/generic/tkbltGrElemLine.C
diff options
context:
space:
mode:
Diffstat (limited to 'tkblt/generic/tkbltGrElemLine.C')
-rw-r--r--tkblt/generic/tkbltGrElemLine.C2405
1 files changed, 0 insertions, 2405 deletions
diff --git a/tkblt/generic/tkbltGrElemLine.C b/tkblt/generic/tkbltGrElemLine.C
deleted file mode 100644
index f8ec8f7..0000000
--- a/tkblt/generic/tkbltGrElemLine.C
+++ /dev/null
@@ -1,2405 +0,0 @@
-/*
- * 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 (c) 1993 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 "tkbltGraph.h"
-#include "tkbltGrElemLine.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 SEARCH_X 0
-#define SEARCH_Y 1
-#define SEARCH_BOTH 2
-
-#define SEARCH_POINTS 0 // closest data point.
-#define SEARCH_TRACES 1 // closest point on trace.
-#define SEARCH_AUTO 2 // traces if linewidth is > 0 and more than one
-
-#define MIN3(a,b,c) (((a)<(b))?(((a)<(c))?(a):(c)):(((b)<(c))?(b):(c)))
-#define PointInRegion(e,x,y) (((x) <= (e)->right) && ((x) >= (e)->left) && ((y) <= (e)->bottom) && ((y) >= (e)->top))
-
-#define BROKEN_TRACE(dir,last,next) (((dir == INCREASING)&&(next < last)) || ((dir == DECREASING)&&(next > last)))
-#define DRAW_SYMBOL() (symbolInterval_==0||(symbolCounter_%symbolInterval_)==0)
-
-static const char* symbolMacros[] =
- {"Li", "Sq", "Ci", "Di", "Pl", "Cr", "Sp", "Sc", "Tr", "Ar", "Bm", NULL};
-
-// OptionSpecs
-
-static const char* smoothObjOption[] =
- {"linear", "step", "cubic", "quadratic", "catrom", NULL};
-
-static const char* penDirObjOption[] =
- {"increasing", "decreasing", "both", NULL};
-
-static Tk_ObjCustomOption styleObjOption =
- {
- "styles", StyleSetProc, StyleGetProc, StyleRestoreProc, StyleFreeProc,
- (ClientData)sizeof(LineStyle)
- };
-
-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(LineElementOptions, activePenPtr),
- TK_OPTION_NULL_OK, &penObjOption, LAYOUT},
- {TK_OPTION_BORDER, "-areabackground", "areaBackground", "AreaBackground",
- NULL, -1, Tk_Offset(LineElementOptions, fillBg),
- TK_OPTION_NULL_OK, NULL, LAYOUT},
- {TK_OPTION_CUSTOM, "-bindtags", "bindTags", "BindTags",
- "all", -1, Tk_Offset(LineElementOptions, tags),
- TK_OPTION_NULL_OK, &listObjOption, 0},
- {TK_OPTION_COLOR, "-color", "color", "Color",
- STD_NORMAL_FOREGROUND, -1,
- Tk_Offset(LineElementOptions, builtinPen.traceColor), 0, NULL, CACHE},
- {TK_OPTION_CUSTOM, "-dashes", "dashes", "Dashes",
- NULL, -1, Tk_Offset(LineElementOptions, builtinPen.traceDashes),
- TK_OPTION_NULL_OK, &dashesObjOption, CACHE},
- {TK_OPTION_CUSTOM, "-data", "data", "Data",
- NULL, -1, Tk_Offset(LineElementOptions, coords),
- TK_OPTION_NULL_OK, &pairsObjOption, RESET},
- {TK_OPTION_COLOR, "-errorbarcolor", "errorBarColor", "ErrorBarColor",
- NULL, -1, Tk_Offset(LineElementOptions, builtinPen.errorBarColor),
- TK_OPTION_NULL_OK, NULL, CACHE},
- {TK_OPTION_PIXELS,"-errorbarwidth", "errorBarWidth", "ErrorBarWidth",
- "1", -1, Tk_Offset(LineElementOptions, builtinPen.errorBarLineWidth),
- 0, NULL, CACHE},
- {TK_OPTION_PIXELS, "-errorbarcap", "errorBarCap", "ErrorBarCap",
- "0", -1, Tk_Offset(LineElementOptions, builtinPen.errorBarCapWidth),
- 0, NULL, LAYOUT},
- {TK_OPTION_COLOR, "-fill", "fill", "Fill",
- NULL, -1, Tk_Offset(LineElementOptions, builtinPen.symbol.fillColor),
- TK_OPTION_NULL_OK, NULL, CACHE},
- {TK_OPTION_BOOLEAN, "-hide", "hide", "Hide",
- "no", -1, Tk_Offset(LineElementOptions, hide), 0, NULL, LAYOUT},
- {TK_OPTION_STRING, "-label", "label", "Label",
- NULL, -1, Tk_Offset(LineElementOptions, label),
- TK_OPTION_NULL_OK | TK_OPTION_DONT_SET_DEFAULT, NULL, LAYOUT},
- {TK_OPTION_RELIEF, "-legendrelief", "legendRelief", "LegendRelief",
- "flat", -1, Tk_Offset(LineElementOptions, legendRelief), 0, NULL, LAYOUT},
- {TK_OPTION_PIXELS, "-linewidth", "lineWidth", "LineWidth",
- "1", -1, Tk_Offset(LineElementOptions, builtinPen.traceWidth),
- 0, NULL, CACHE},
- {TK_OPTION_CUSTOM, "-mapx", "mapX", "MapX",
- "x", -1, Tk_Offset(LineElementOptions, xAxis), 0, &xAxisObjOption, RESET},
- {TK_OPTION_CUSTOM, "-mapy", "mapY", "MapY",
- "y", -1, Tk_Offset(LineElementOptions, yAxis), 0, &yAxisObjOption, RESET},
- {TK_OPTION_INT, "-maxsymbols", "maxSymbols", "MaxSymbols",
- "0", -1, Tk_Offset(LineElementOptions, reqMaxSymbols), 0, NULL, CACHE},
- {TK_OPTION_COLOR, "-offdash", "offDash", "OffDash",
- NULL, -1, Tk_Offset(LineElementOptions, builtinPen.traceOffColor),
- TK_OPTION_NULL_OK, NULL, CACHE},
- {TK_OPTION_COLOR, "-outline", "outline", "Outline",
- NULL, -1, Tk_Offset(LineElementOptions, builtinPen.symbol.outlineColor),
- TK_OPTION_NULL_OK, NULL, CACHE},
- {TK_OPTION_PIXELS, "-outlinewidth", "outlineWidth", "OutlineWidth",
- "1", -1, Tk_Offset(LineElementOptions, builtinPen.symbol.outlineWidth),
- 0, NULL, CACHE},
- {TK_OPTION_CUSTOM, "-pen", "pen", "Pen",
- NULL, -1, Tk_Offset(LineElementOptions, normalPenPtr),
- TK_OPTION_NULL_OK, &penObjOption, LAYOUT},
- {TK_OPTION_PIXELS, "-pixels", "pixels", "Pixels",
- "0.1i", -1, Tk_Offset(LineElementOptions, builtinPen.symbol.size),
- 0, NULL, LAYOUT},
- {TK_OPTION_DOUBLE, "-reduce", "reduce", "Reduce",
- "0", -1, Tk_Offset(LineElementOptions, rTolerance), 0, NULL, RESET},
- {TK_OPTION_BOOLEAN, "-scalesymbols", "scaleSymbols", "ScaleSymbols",
- "yes", -1, Tk_Offset(LineElementOptions, scaleSymbols), 0, NULL, LAYOUT},
- {TK_OPTION_STRING_TABLE, "-showerrorbars", "showErrorBars", "ShowErrorBars",
- "both", -1, Tk_Offset(LineElementOptions, builtinPen.errorBarShow),
- 0, &fillObjOption, LAYOUT},
- {TK_OPTION_STRING_TABLE, "-showvalues", "showValues", "ShowValues",
- "none", -1, Tk_Offset(LineElementOptions, builtinPen.valueShow),
- 0, &fillObjOption, CACHE},
- {TK_OPTION_STRING_TABLE, "-smooth", "smooth", "Smooth",
- "linear", -1, Tk_Offset(LineElementOptions, reqSmooth),
- 0, &smoothObjOption, LAYOUT},
- {TK_OPTION_CUSTOM, "-styles", "styles", "Styles",
- "", -1, Tk_Offset(LineElementOptions, stylePalette),
- 0, &styleObjOption, RESET},
- {TK_OPTION_STRING_TABLE, "-symbol", "symbol", "Symbol",
- "none", -1, Tk_Offset(LineElementOptions, builtinPen.symbol),
- 0, &symbolObjOption, CACHE},
- {TK_OPTION_STRING_TABLE, "-trace", "trace", "Trace",
- "both", -1, Tk_Offset(LineElementOptions, penDir),
- 0, &penDirObjOption, RESET},
- {TK_OPTION_ANCHOR, "-valueanchor", "valueAnchor", "ValueAnchor",
- "s", -1, Tk_Offset(LineElementOptions, builtinPen.valueStyle.anchor),
- 0, NULL, CACHE},
- {TK_OPTION_COLOR, "-valuecolor", "valueColor", "ValueColor",
- STD_NORMAL_FOREGROUND,-1,
- Tk_Offset(LineElementOptions, builtinPen.valueStyle.color),
- 0, NULL, CACHE},
- {TK_OPTION_FONT, "-valuefont", "valueFont", "ValueFont",
- STD_FONT_SMALL, -1,
- Tk_Offset(LineElementOptions, builtinPen.valueStyle.font),
- 0, NULL, CACHE},
- {TK_OPTION_STRING, "-valueformat", "valueFormat", "ValueFormat",
- "%g", -1, Tk_Offset(LineElementOptions, builtinPen.valueFormat),
- TK_OPTION_NULL_OK, NULL, CACHE},
- {TK_OPTION_DOUBLE, "-valuerotate", "valueRotate", "ValueRotate",
- "0", -1, Tk_Offset(LineElementOptions, builtinPen.valueStyle.angle),
- 0, NULL, CACHE},
- {TK_OPTION_CUSTOM, "-weights", "weights", "Weights",
- NULL, -1, Tk_Offset(LineElementOptions, 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(LineElementOptions, coords.x),
- TK_OPTION_NULL_OK, &valuesObjOption, RESET},
- {TK_OPTION_CUSTOM, "-xerror", "xError", "XError",
- NULL, -1, Tk_Offset(LineElementOptions, xError),
- TK_OPTION_NULL_OK, &valuesObjOption, RESET},
- {TK_OPTION_CUSTOM, "-xhigh", "xHigh", "XHigh",
- NULL, -1, Tk_Offset(LineElementOptions, xHigh),
- TK_OPTION_NULL_OK, &valuesObjOption, RESET},
- {TK_OPTION_CUSTOM, "-xlow", "xLow", "XLow",
- NULL, -1, Tk_Offset(LineElementOptions, 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(LineElementOptions, coords.y),
- TK_OPTION_NULL_OK, &valuesObjOption, RESET},
- {TK_OPTION_CUSTOM, "-yerror", "yError", "YError",
- NULL, -1, Tk_Offset(LineElementOptions, yError),
- TK_OPTION_NULL_OK, &valuesObjOption, RESET},
- {TK_OPTION_CUSTOM, "-yhigh", "yHigh", "YHigh",
- NULL, -1, Tk_Offset(LineElementOptions, yHigh),
- TK_OPTION_NULL_OK, &valuesObjOption, RESET},
- {TK_OPTION_CUSTOM, "-ylow", "yLow", "YLow",
- NULL, -1, Tk_Offset(LineElementOptions, yLow),
- TK_OPTION_NULL_OK, &valuesObjOption, RESET},
- {TK_OPTION_END, NULL, NULL, NULL, NULL, 0, -1, 0, 0, 0}
-};
-
-LineElement::LineElement(Graph* graphPtr, const char* name, Tcl_HashEntry* hPtr)
- : Element(graphPtr, name, hPtr)
-{
- smooth_ = LINEAR;
- fillPts_ =NULL;
- nFillPts_ = 0;
-
- symbolPts_.points =NULL;
- symbolPts_.length =0;
- symbolPts_.map =NULL;
- activePts_.points =NULL;
- activePts_.length =0;
- activePts_.map =NULL;
-
- xeb_.segments =NULL;
- xeb_.map =NULL;
- xeb_.length =0;
- yeb_.segments =NULL;
- yeb_.map =NULL;
- yeb_.length =0;
-
- symbolInterval_ =0;
- symbolCounter_ =0;
- traces_ =NULL;
-
- ops_ = (LineElementOptions*)calloc(1, sizeof(LineElementOptions));
- LineElementOptions* ops = (LineElementOptions*)ops_;
- ops->elemPtr = (Element*)this;
-
- builtinPenPtr = new LinePen(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_);
-}
-
-LineElement::~LineElement()
-{
- LineElementOptions* ops = (LineElementOptions*)ops_;
-
- delete builtinPenPtr;
-
- reset();
-
- if (ops->stylePalette) {
- freeStylePalette(ops->stylePalette);
- delete ops->stylePalette;
- }
-
- delete [] fillPts_;
-}
-
-int LineElement::configure()
-{
- LineElementOptions* ops = (LineElementOptions*)ops_;
-
- if (builtinPenPtr->configure() != TCL_OK)
- return TCL_ERROR;
-
- // Point to the static normal/active pens if no external pens have been
- // selected.
- ChainLink* link = Chain_FirstLink(ops->stylePalette);
- if (!link) {
- link = new ChainLink(sizeof(LineStyle));
- ops->stylePalette->linkAfter(link, NULL);
- }
- LineStyle* stylePtr = (LineStyle*)Chain_GetValue(link);
- stylePtr->penPtr = NORMALPEN(ops);
-
- return TCL_OK;
-}
-
-void LineElement::map()
-{
- LineElementOptions* ops = (LineElementOptions*)ops_;
-
- if (!link)
- return;
-
- reset();
- if (!ops->coords.x || !ops->coords.y ||
- !ops->coords.x->nValues() || !ops->coords.y->nValues())
- return;
-
- MapInfo mi;
- getScreenPoints(&mi);
- mapSymbols(&mi);
-
- if (nActiveIndices_ > 0)
- mapActiveSymbols();
-
- // Map connecting line segments if they are to be displayed.
- smooth_ = (Smoothing)ops->reqSmooth;
- if ((mi.nScreenPts > 1) && (ops->builtinPen.traceWidth > 0)) {
- // Do smoothing if necessary. This can extend the coordinate array,
- // so both mi.points and mi.nPoints may change.
- switch (smooth_) {
- case STEP:
- generateSteps(&mi);
- break;
-
- case CUBIC:
- case QUADRATIC:
- // Can't interpolate with less than three points
- if (mi.nScreenPts < 3)
- smooth_ = LINEAR;
- else
- generateSpline(&mi);
- break;
-
- case CATROM:
- // Can't interpolate with less than three points
- if (mi.nScreenPts < 3)
- smooth_ = LINEAR;
- else
- generateParametricSpline(&mi);
- break;
-
- default:
- break;
- }
- if (ops->rTolerance > 0.0)
- reducePoints(&mi, ops->rTolerance);
-
- if (ops->fillBg)
- mapFillArea(&mi);
-
- mapTraces(&mi);
- }
- delete [] mi.screenPts;
- delete [] mi.map;
-
- // Set the symbol size of all the pen styles
- for (ChainLink* link = Chain_FirstLink(ops->stylePalette); link;
- link = Chain_NextLink(link)) {
- LineStyle* stylePtr = (LineStyle*)Chain_GetValue(link);
- LinePen* penPtr = (LinePen *)stylePtr->penPtr;
- LinePenOptions* penOps = (LinePenOptions*)penPtr->ops();
- int size = scaleSymbol(penOps->symbol.size);
- stylePtr->symbolSize = size;
- stylePtr->errorBarCapWidth = penOps->errorBarCapWidth;
- }
-
- LineStyle** styleMap = (LineStyle**)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(styleMap);
- }
-
- mergePens(styleMap);
- delete [] styleMap;
-}
-
-void LineElement::extents(Region2d *extsPtr)
-{
- LineElementOptions* ops = (LineElementOptions*)ops_;
-
- extsPtr->top = extsPtr->left = DBL_MAX;
- extsPtr->bottom = extsPtr->right = -DBL_MAX;
-
- if (!ops->coords.x || !ops->coords.y ||
- !ops->coords.x->nValues() || !ops->coords.y->nValues())
- return;
- int np = NUMBEROFPOINTS(ops);
-
- extsPtr->right = ops->coords.x->max();
- AxisOptions* axisxops = (AxisOptions*)ops->xAxis->ops();
- if ((ops->coords.x->min() <= 0.0) && (axisxops->logScale))
- extsPtr->left = FindElemValuesMinimum(ops->coords.x, DBL_MIN);
- else
- extsPtr->left = ops->coords.x->min();
-
- extsPtr->bottom = ops->coords.y->max();
- AxisOptions* axisyops = (AxisOptions*)ops->yAxis->ops();
- if ((ops->coords.y->min() <= 0.0) && (axisyops->logScale))
- extsPtr->top = FindElemValuesMinimum(ops->coords.y, DBL_MIN);
- else
- extsPtr->top = ops->coords.y->min();
-
- // Correct the data limits for error bars
- if (ops->xError && ops->xError->nValues() > 0) {
- np = MIN(ops->xError->nValues(), np);
- for (int ii=0; ii<np; ii++) {
- double x = ops->coords.x->values_[ii] + ops->xError->values_[ii];
- if (x > extsPtr->right)
- extsPtr->right = x;
-
- x = ops->coords.x->values_[ii] - ops->xError->values_[ii];
- AxisOptions* axisxops = (AxisOptions*)ops->xAxis->ops();
- if (axisxops->logScale) {
- // Mirror negative values, instead of ignoring them
- if (x < 0.0)
- x = -x;
- if ((x > DBL_MIN) && (x < extsPtr->left))
- extsPtr->left = x;
- }
- else if (x < extsPtr->left)
- extsPtr->left = x;
- }
- }
- else {
- if (ops->xHigh &&
- (ops->xHigh->nValues() > 0) &&
- (ops->xHigh->max() > extsPtr->right)) {
- extsPtr->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 < extsPtr->left)
- extsPtr->left = left;
- }
- }
-
- if (ops->yError && ops->yError->nValues() > 0) {
- np = MIN(ops->yError->nValues(), np);
- for (int ii=0; ii<np; ii++) {
- double y = ops->coords.y->values_[ii] + ops->yError->values_[ii];
- if (y > extsPtr->bottom)
- extsPtr->bottom = y;
-
- y = ops->coords.y->values_[ii] - ops->yError->values_[ii];
- AxisOptions* axisyops = (AxisOptions*)ops->yAxis->ops();
- if (axisyops->logScale) {
- // Mirror negative values, instead of ignoring them
- if (y < 0.0)
- y = -y;
- if ((y > DBL_MIN) && (y < extsPtr->left))
- extsPtr->top = y;
- }
- else if (y < extsPtr->top)
- extsPtr->top = y;
- }
- }
- else {
- if (ops->yHigh && (ops->yHigh->nValues() > 0) &&
- (ops->yHigh->max() > extsPtr->bottom))
- extsPtr->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 < extsPtr->top)
- extsPtr->top = top;
- }
- }
-}
-
-void LineElement::closest()
-{
- LineElementOptions* ops = (LineElementOptions*)ops_;
- GraphOptions* gops = (GraphOptions*)graphPtr_->ops_;
-
- ClosestSearch* searchPtr = &gops->search;
- int mode = searchPtr->mode;
- if (mode == SEARCH_AUTO) {
- LinePen* penPtr = NORMALPEN(ops);
- LinePenOptions* penOps = (LinePenOptions*)penPtr->ops();
- mode = SEARCH_POINTS;
- if ((NUMBEROFPOINTS(ops) > 1) && (penOps->traceWidth > 0))
- mode = SEARCH_TRACES;
- }
- if (mode == SEARCH_POINTS)
- closestPoint(searchPtr);
- else {
- int found = closestTrace();
- if ((!found) && (searchPtr->along != SEARCH_BOTH))
- closestPoint(searchPtr);
- }
-}
-
-void LineElement::draw(Drawable drawable)
-{
- LineElementOptions* ops = (LineElementOptions*)ops_;
- LinePen* penPtr = NORMALPEN(ops);
- LinePenOptions* penOps = (LinePenOptions*)penPtr->ops();
-
- if (ops->hide)
- return;
-
- // Fill area under the curve
- if (ops->fillBg && fillPts_) {
- XPoint*points = new XPoint[nFillPts_];
-
- unsigned int count =0;
- for (Point2d *pp = fillPts_, *endp = pp + nFillPts_; pp < endp; pp++) {
- points[count].x = (short)pp->x;
- points[count].y = (short)pp->y;
- count++;
- }
- Tk_Fill3DPolygon(graphPtr_->tkwin_, drawable, ops->fillBg, points,
- nFillPts_, 0, TK_RELIEF_FLAT);
- delete [] points;
- }
-
- // Error bars
- for (ChainLink* link = Chain_FirstLink(ops->stylePalette); link;
- link = Chain_NextLink(link)) {
- LineStyle* stylePtr = (LineStyle*)Chain_GetValue(link);
- LinePen* penPtr = (LinePen *)stylePtr->penPtr;
- LinePenOptions* penOps = (LinePenOptions*)penPtr->ops();
-
- if ((stylePtr->xeb.length > 0) && (penOps->errorBarShow & SHOW_X))
- graphPtr_->drawSegments(drawable, penPtr->errorBarGC_,
- stylePtr->xeb.segments, stylePtr->xeb.length);
-
- if ((stylePtr->yeb.length > 0) && (penOps->errorBarShow & SHOW_Y))
- graphPtr_->drawSegments(drawable, penPtr->errorBarGC_,
- stylePtr->yeb.segments, stylePtr->yeb.length);
- }
-
- // traces
- if ((Chain_GetLength(traces_) > 0) && (penOps->traceWidth > 0))
- drawTraces(drawable, penPtr);
-
- // Symbols, values
- if (ops->reqMaxSymbols > 0) {
- int total = 0;
- for (ChainLink* link = Chain_FirstLink(ops->stylePalette); link;
- link = Chain_NextLink(link)) {
- LineStyle *stylePtr = (LineStyle*)Chain_GetValue(link);
- total += stylePtr->symbolPts.length;
- }
- symbolInterval_ = total / ops->reqMaxSymbols;
- symbolCounter_ = 0;
- }
-
- unsigned int count =0;
- for (ChainLink* link = Chain_FirstLink(ops->stylePalette); link;
- link = Chain_NextLink(link)) {
- LineStyle* stylePtr = (LineStyle*)Chain_GetValue(link);
- LinePen* penPtr = (LinePen *)stylePtr->penPtr;
- LinePenOptions* penOps = (LinePenOptions*)penPtr->ops();
-
- if ((stylePtr->symbolPts.length > 0) &&
- (penOps->symbol.type != SYMBOL_NONE))
- drawSymbols(drawable, penPtr, stylePtr->symbolSize,
- stylePtr->symbolPts.length, stylePtr->symbolPts.points);
-
- if (penOps->valueShow != SHOW_NONE)
- drawValues(drawable, penPtr, stylePtr->symbolPts.length,
- stylePtr->symbolPts.points, symbolPts_.map + count);
-
- count += stylePtr->symbolPts.length;
- }
-
- symbolInterval_ = 0;
- symbolCounter_ = 0;
-}
-
-void LineElement::drawActive(Drawable drawable)
-{
- LineElementOptions* ops = (LineElementOptions*)ops_;
- LinePen* penPtr = (LinePen*)ops->activePenPtr;
- if (!penPtr)
- return;
- LinePenOptions* penOps = (LinePenOptions*)penPtr->ops();
-
- if (ops->hide || !active_)
- return;
-
- int symbolSize = scaleSymbol(penOps->symbol.size);
-
- if (nActiveIndices_ > 0) {
- mapActiveSymbols();
-
- if (penOps->symbol.type != SYMBOL_NONE)
- drawSymbols(drawable, penPtr, symbolSize, activePts_.length,
- activePts_.points);
- if (penOps->valueShow != SHOW_NONE)
- drawValues(drawable, penPtr, activePts_.length, activePts_.points,
- activePts_.map);
- }
- else if (nActiveIndices_ < 0) {
- if ((Chain_GetLength(traces_) > 0) && (penOps->traceWidth > 0))
- drawTraces(drawable, penPtr);
-
- if (penOps->symbol.type != SYMBOL_NONE)
- drawSymbols(drawable, penPtr, symbolSize, symbolPts_.length,
- symbolPts_.points);
-
- if (penOps->valueShow != SHOW_NONE) {
- drawValues(drawable, penPtr, symbolPts_.length, symbolPts_.points,
- symbolPts_.map);
- }
- }
-}
-
-void LineElement::drawSymbol(Drawable drawable, int x, int y, int size)
-{
- LineElementOptions* ops = (LineElementOptions*)ops_;
-
- LinePen* penPtr = NORMALPEN(ops);
- LinePenOptions* penOps = (LinePenOptions*)penPtr->ops();
-
- if (penOps->traceWidth > 0) {
- // Draw an extra line offset by one pixel from the previous to give a
- // thicker appearance. This is only for the legend entry. This routine
- // is never called for drawing the actual line segments.
- XDrawLine(graphPtr_->display_, drawable, penPtr->traceGC_, x - size, y,
- x + size, y);
- XDrawLine(graphPtr_->display_, drawable, penPtr->traceGC_, x - size, y + 1,
- x + size, y + 1);
- }
- if (penOps->symbol.type != SYMBOL_NONE) {
- Point2d point;
- point.x = x;
- point.y = y;
- drawSymbols(drawable, penPtr, size, 1, &point);
- }
-}
-
-void LineElement::print(PSOutput* psPtr)
-{
- LineElementOptions* ops = (LineElementOptions*)ops_;
- LinePen* penPtr = NORMALPEN(ops);
- LinePenOptions* penOps = (LinePenOptions*)penPtr->ops();
-
- if (ops->hide)
- return;
-
- psPtr->format("\n%% Element \"%s\"\n\n", name_);
-
- // Draw fill area
- if (ops->fillBg && fillPts_) {
- psPtr->append("% start fill area\n");
- psPtr->setBackground(ops->fillBg);
- psPtr->printPolyline(fillPts_, nFillPts_);
- psPtr->append("gsave fill grestore\n");
- psPtr->append("% end fill area\n");
- }
-
- // traces
- if ((Chain_GetLength(traces_) > 0) && (penOps->traceWidth > 0))
- printTraces(psPtr, penPtr);
-
- // Symbols, error bars, values
- if (ops->reqMaxSymbols > 0) {
- int total = 0;
- for (ChainLink* link = Chain_FirstLink(ops->stylePalette); link;
- link = Chain_NextLink(link)) {
- LineStyle *stylePtr = (LineStyle*)Chain_GetValue(link);
- total += stylePtr->symbolPts.length;
- }
- symbolInterval_ = total / ops->reqMaxSymbols;
- symbolCounter_ = 0;
- }
-
- unsigned int count =0;
- for (ChainLink* link = Chain_FirstLink(ops->stylePalette); link;
- link = Chain_NextLink(link)) {
- LineStyle *stylePtr = (LineStyle*)Chain_GetValue(link);
- LinePen* penPtr = (LinePen *)stylePtr->penPtr;
- LinePenOptions* penOps = (LinePenOptions*)penPtr->ops();
- XColor* colorPtr = penOps->errorBarColor;
- if (!colorPtr)
- colorPtr = penOps->traceColor;
-
- if ((stylePtr->xeb.length > 0) && (penOps->errorBarShow & SHOW_X)) {
- psPtr->setLineAttributes(colorPtr, penOps->errorBarLineWidth,
- NULL, CapButt, JoinMiter);
- psPtr->printSegments(stylePtr->xeb.segments, stylePtr->xeb.length);
- }
-
- if ((stylePtr->yeb.length > 0) && (penOps->errorBarShow & SHOW_Y)) {
- psPtr->setLineAttributes(colorPtr, penOps->errorBarLineWidth,
- NULL, CapButt, JoinMiter);
- psPtr->printSegments(stylePtr->yeb.segments, stylePtr->yeb.length);
- }
-
- if ((stylePtr->symbolPts.length > 0) &&
- (penOps->symbol.type != SYMBOL_NONE))
- printSymbols(psPtr, penPtr, stylePtr->symbolSize,
- stylePtr->symbolPts.length, stylePtr->symbolPts.points);
-
- if (penOps->valueShow != SHOW_NONE)
- printValues(psPtr, penPtr, stylePtr->symbolPts.length,
- stylePtr->symbolPts.points, symbolPts_.map + count);
-
- count += stylePtr->symbolPts.length;
- }
-
- symbolInterval_ = 0;
- symbolCounter_ = 0;
-}
-
-void LineElement::printActive(PSOutput* psPtr)
-{
- LineElementOptions* ops = (LineElementOptions*)ops_;
- LinePen* penPtr = (LinePen *)ops->activePenPtr;
- if (!penPtr)
- return;
- LinePenOptions* penOps = (LinePenOptions*)penPtr->ops();
-
- if (ops->hide || !active_)
- return;
-
- psPtr->format("\n%% Active Element \"%s\"\n\n", name_);
-
- int symbolSize = scaleSymbol(penOps->symbol.size);
- if (nActiveIndices_ > 0) {
- mapActiveSymbols();
-
- if (penOps->symbol.type != SYMBOL_NONE)
- printSymbols(psPtr, penPtr, symbolSize, activePts_.length,
- activePts_.points);
-
- if (penOps->valueShow != SHOW_NONE)
- printValues(psPtr, penPtr, activePts_.length, activePts_.points,
- activePts_.map);
- }
- else if (nActiveIndices_ < 0) {
- if ((Chain_GetLength(traces_) > 0) && (penOps->traceWidth > 0))
- printTraces(psPtr, (LinePen*)penPtr);
-
- if (penOps->symbol.type != SYMBOL_NONE)
- printSymbols(psPtr, penPtr, symbolSize, symbolPts_.length,
- symbolPts_.points);
- if (penOps->valueShow != SHOW_NONE) {
- printValues(psPtr, penPtr, symbolPts_.length, symbolPts_.points,
- symbolPts_.map);
- }
- }
-}
-
-void LineElement::printSymbol(PSOutput* psPtr, double x, double y, int size)
-{
- LineElementOptions* ops = (LineElementOptions*)ops_;
-
- LinePen* penPtr = NORMALPEN(ops);
- LinePenOptions* penOps = (LinePenOptions*)penPtr->ops();
-
- if (penOps->traceWidth > 0) {
- // Draw an extra line offset by one pixel from the previous to give a
- // thicker appearance. This is only for the legend entry. This routine
- // is never called for drawing the actual line segments.
- psPtr->setLineAttributes(penOps->traceColor, penOps->traceWidth,
- &penOps->traceDashes, CapButt, JoinMiter);
- psPtr->format("%g %g %d Li\n", x, y, size + size);
- }
-
- if (penOps->symbol.type != SYMBOL_NONE) {
- Point2d point;
- point.x = x;
- point.y = y;
- printSymbols(psPtr, penPtr, size, 1, &point);
- }
-}
-
-// Support
-
-double LineElement::distanceToLine(int x, int y, Point2d *p, Point2d *q,
- Point2d *t)
-{
- double right, left, top, bottom;
-
- *t = getProjection(x, y, p, q);
- if (p->x > q->x)
- right = p->x, left = q->x;
- else
- left = p->x, right = q->x;
-
- if (p->y > q->y)
- bottom = p->y, top = q->y;
- else
- top = p->y, bottom = q->y;
-
- 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;
-
- return hypot((t->x - x), (t->y - y));
-}
-
-double LineElement::distanceToX(int x, int y, Point2d *p, Point2d *q,
- Point2d *t)
-{
- double dx, dy;
- double d;
-
- if (p->x > q->x) {
- if ((x > p->x) || (x < q->x)) {
- return DBL_MAX; /* X-coordinate outside line segment. */
- }
- } else {
- if ((x > q->x) || (x < p->x)) {
- return DBL_MAX; /* X-coordinate outside line segment. */
- }
- }
- dx = p->x - q->x;
- dy = p->y - q->y;
- t->x = (double)x;
- if (fabs(dx) < DBL_EPSILON) {
- double d1, d2;
- /*
- * Same X-coordinate indicates a vertical line. Pick the closest end
- * point.
- */
- d1 = p->y - y;
- d2 = q->y - y;
- if (fabs(d1) < fabs(d2)) {
- t->y = p->y, d = d1;
- } else {
- t->y = q->y, d = d2;
- }
- }
- else if (fabs(dy) < DBL_EPSILON) {
- /* Horizontal line. */
- t->y = p->y, d = p->y - y;
- }
- else {
- double m = dy / dx;
- double b = p->y - (m * p->x);
- t->y = (x * m) + b;
- d = y - t->y;
- }
-
- return fabs(d);
-}
-
-double LineElement::distanceToY(int x, int y, Point2d *p, Point2d *q,
- Point2d *t)
-{
- double dx, dy;
- double d;
-
- if (p->y > q->y) {
- if ((y > p->y) || (y < q->y)) {
- return DBL_MAX;
- }
- }
- else {
- if ((y > q->y) || (y < p->y)) {
- return DBL_MAX;
- }
- }
- dx = p->x - q->x;
- dy = p->y - q->y;
- t->y = y;
- if (fabs(dy) < DBL_EPSILON) {
- double d1, d2;
-
- /* Save Y-coordinate indicates an horizontal line. Pick the closest end
- * point. */
- d1 = p->x - x;
- d2 = q->x - x;
- if (fabs(d1) < fabs(d2)) {
- t->x = p->x, d = d1;
- }
- else {
- t->x = q->x, d = d2;
- }
- }
- else if (fabs(dx) < DBL_EPSILON) {
- /* Vertical line. */
- t->x = p->x, d = p->x - x;
- }
- else {
- double m = dy / dx;
- double b = p->y - (m * p->x);
- t->x = (y - b) / m;
- d = x - t->x;
- }
-
- return fabs(d);
-}
-
-int LineElement::scaleSymbol(int normalSize)
-{
- LineElementOptions* ops = (LineElementOptions*)ops_;
-
- double scale = 1.0;
- if (ops->scaleSymbols) {
- double xRange = (ops->xAxis->max_ - ops->xAxis->min_);
- double yRange = (ops->yAxis->max_ - ops->yAxis->min_);
- // Save the ranges as a baseline for future scaling
- if (!xRange_ || !yRange_) {
- xRange_ = xRange;
- yRange_ = yRange;
- }
- else {
- // Scale the symbol by the smallest change in the X or Y axes
- double xScale = xRange_ / xRange;
- double yScale = yRange_ / yRange;
- scale = MIN(xScale, yScale);
- }
- }
- int newSize = (int)(normalSize * scale);
-
- int maxSize = MIN(graphPtr_->hRange_, graphPtr_->vRange_);
- if (newSize > maxSize)
- newSize = maxSize;
-
- // Make the symbol size odd so that its center is a single pixel.
- newSize |= 0x01;
-
- return newSize;
-}
-
-void LineElement::getScreenPoints(MapInfo* mapPtr)
-{
- LineElementOptions* ops = (LineElementOptions*)ops_;
- GraphOptions* gops = (GraphOptions*)graphPtr_->ops_;
-
- if (!ops->coords.x || !ops->coords.y) {
- mapPtr->screenPts = NULL;
- mapPtr->nScreenPts = 0;
- mapPtr->map = NULL;
- }
-
- int np = NUMBEROFPOINTS(ops);
- double* x = ops->coords.x->values_;
- double* y = ops->coords.y->values_;
- Point2d* points = new Point2d[np];
- int* map = new int[np];
-
- int count = 0;
- if (gops->inverted) {
- for (int ii=0; ii<np; ii++) {
- if ((isfinite(x[ii])) && (isfinite(y[ii]))) {
- points[count].x = ops->yAxis->hMap(y[ii]);
- points[count].y = ops->xAxis->vMap(x[ii]);
- map[count] = ii;
- count++;
- }
- }
- }
- else {
- for (int ii=0; ii< np; ii++) {
- if ((isfinite(x[ii])) && (isfinite(y[ii]))) {
- points[count].x = ops->xAxis->hMap(x[ii]);
- points[count].y = ops->yAxis->vMap(y[ii]);
- map[count] = ii;
- count++;
- }
- }
- }
- mapPtr->screenPts = points;
- mapPtr->nScreenPts = count;
- mapPtr->map = map;
-}
-
-void LineElement::reducePoints(MapInfo *mapPtr, double tolerance)
-{
- int* simple = new int[mapPtr->nScreenPts];
- int* map = new int[mapPtr->nScreenPts];
- Point2d* screenPts = new Point2d[mapPtr->nScreenPts];
- int np = simplify(mapPtr->screenPts, 0, mapPtr->nScreenPts - 1,
- tolerance, simple);
- for (int ii=0; ii<np; ii++) {
- int kk = simple[ii];
- screenPts[ii] = mapPtr->screenPts[kk];
- map[ii] = mapPtr->map[kk];
- }
- delete [] simple;
-
- delete [] mapPtr->screenPts;
- mapPtr->screenPts = screenPts;
- delete [] mapPtr->map;
- mapPtr->map = map;
- mapPtr->nScreenPts = np;
-}
-
-// Douglas-Peucker line simplification algorithm
-int LineElement::simplify(Point2d *inputPts, int low, int high,
- double tolerance, int *indices)
-{
-#define StackPush(a) s++, stack[s] = (a)
-#define StackPop(a) (a) = stack[s], s--
-#define StackEmpty() (s < 0)
-#define StackTop() stack[s]
- int split = -1;
- double dist2, tolerance2;
- int s = -1; /* Points to top stack item. */
-
- int* stack = new int[high - low + 1];
- StackPush(high);
- int count = 0;
- indices[count++] = 0;
- tolerance2 = tolerance * tolerance;
- while (!StackEmpty()) {
- dist2 = findSplit(inputPts, low, StackTop(), &split);
- if (dist2 > tolerance2)
- StackPush(split);
- else {
- indices[count++] = StackTop();
- StackPop(low);
- }
- }
- delete [] stack;
- return count;
-}
-
-double LineElement::findSplit(Point2d *points, int i, int j, int *split)
-{
- double maxDist2 = -1.0;
- if ((i + 1) < j) {
- double a = points[i].y - points[j].y;
- double b = points[j].x - points[i].x;
- double c = (points[i].x * points[j].y) - (points[i].y * points[j].x);
- for (int kk = (i + 1); kk < j; kk++) {
- double dist2 = (points[kk].x * a) + (points[kk].y * b) + c;
- if (dist2 < 0.0)
- dist2 = -dist2;
-
- // Track the maximum.
- if (dist2 > maxDist2) {
- maxDist2 = dist2;
- *split = kk;
- }
- }
- // Correction for segment length---should be redone if can == 0
- maxDist2 *= maxDist2 / (a * a + b * b);
- }
- return maxDist2;
-}
-
-void LineElement::generateSteps(MapInfo *mapPtr)
-{
- int newSize = ((mapPtr->nScreenPts - 1) * 2) + 1;
- Point2d* screenPts = new Point2d[newSize];
- int* map = new int[newSize];
- screenPts[0] = mapPtr->screenPts[0];
- map[0] = 0;
-
- int count = 1;
- for (int i = 1; i < mapPtr->nScreenPts; i++) {
- screenPts[count + 1] = mapPtr->screenPts[i];
-
- // Hold last y-coordinate, use new x-coordinate
- screenPts[count].x = screenPts[count + 1].x;
- screenPts[count].y = screenPts[count - 1].y;
-
- // Use the same style for both the hold and the step points
- map[count] = map[count + 1] = mapPtr->map[i];
- count += 2;
- }
- delete [] mapPtr->map;
- mapPtr->map = map;
- delete [] mapPtr->screenPts;
- mapPtr->screenPts = screenPts;
- mapPtr->nScreenPts = newSize;
-}
-
-void LineElement::generateSpline(MapInfo *mapPtr)
-{
- int nOrigPts = mapPtr->nScreenPts;
- Point2d* origPts = mapPtr->screenPts;
-
- // check points are not monotonically increasing
- for (int ii=0, jj=1; jj<nOrigPts; ii++, jj++) {
- if (origPts[jj].x <= origPts[ii].x)
- return;
- }
- if (((origPts[0].x > (double)graphPtr_->right_)) ||
- ((origPts[mapPtr->nScreenPts - 1].x < (double)graphPtr_->left_)))
- return;
-
- // The spline is computed in screen coordinates instead of data points so
- // that we can select the abscissas of the interpolated points from each
- // pixel horizontally across the plotting area.
- int extra = (graphPtr_->right_ - graphPtr_->left_) + 1;
- if (extra < 1)
- return;
-
- int niPts = nOrigPts + extra + 1;
- Point2d* iPts = new Point2d[niPts];
- int* map = new int[niPts];
-
- // Populate the x2 array with both the original X-coordinates and extra
- // X-coordinates for each horizontal pixel that the line segment contains
- int count = 0;
- for (int ii=0, jj=1; jj<nOrigPts; ii++, jj++) {
- // Add the original x-coordinate
- iPts[count].x = origPts[ii].x;
-
- // Include the starting offset of the point in the offset array
- map[count] = mapPtr->map[ii];
- count++;
-
- // Is any part of the interval (line segment) in the plotting area?
- if ((origPts[jj].x >= (double)graphPtr_->left_) ||
- (origPts[ii].x <= (double)graphPtr_->right_)) {
- double x = origPts[ii].x + 1.0;
-
- /*
- * Since the line segment may be partially clipped on the left or
- * right side, the points to interpolate are always interior to
- * the plotting area.
- *
- * left right
- * x1----|---------------------------|---x2
- *
- * Pick the max of the starting X-coordinate and the left edge and
- * the min of the last X-coordinate and the right edge.
- */
- x = MAX(x, (double)graphPtr_->left_);
- double last = MIN(origPts[jj].x, (double)graphPtr_->right_);
-
- // Add the extra x-coordinates to the interval
- while (x < last) {
- map[count] = mapPtr->map[ii];
- iPts[count++].x = x;
- x++;
- }
- }
- }
- niPts = count;
- int result = 0;
- if (smooth_ == CUBIC)
- result = naturalSpline(origPts, nOrigPts, iPts, niPts);
- else if (smooth_ == QUADRATIC)
- result = quadraticSpline(origPts, nOrigPts, iPts, niPts);
-
- // The spline interpolation failed. We will fall back to the current
- // coordinates and do no smoothing (standard line segments)
- if (!result) {
- smooth_ = LINEAR;
- delete [] iPts;
- delete [] map;
- }
- else {
- delete [] mapPtr->map;
- mapPtr->map = map;
- delete [] mapPtr->screenPts;
- mapPtr->screenPts = iPts;
- mapPtr->nScreenPts = niPts;
- }
-}
-
-void LineElement::generateParametricSpline(MapInfo *mapPtr)
-{
- int nOrigPts = mapPtr->nScreenPts;
- Point2d *origPts = mapPtr->screenPts;
-
- Region2d exts;
- graphPtr_->extents(&exts);
-
- /*
- * Populate the x2 array with both the original X-coordinates and extra
- * X-coordinates for each horizontal pixel that the line segment contains.
- */
- int count = 1;
- for (int i = 0, j = 1; j < nOrigPts; i++, j++) {
- Point2d p = origPts[i];
- Point2d q = origPts[j];
- count++;
- if (lineRectClip(&exts, &p, &q))
- count += (int)(hypot(q.x - p.x, q.y - p.y) * 0.5);
- }
- int niPts = count;
- Point2d *iPts = new Point2d[niPts];
- int* map = new int[niPts];
-
- /*
- * FIXME: This is just plain wrong. The spline should be computed
- * and evaluated in separate steps. This will mean breaking
- * up this routine since the catrom coefficients can be
- * independently computed for original data point. This
- * also handles the problem of allocating enough points
- * since evaluation is independent of the number of points
- * to be evalualted. The interpolated
- * line segments should be clipped, not the original segments.
- */
- count = 0;
- int i,j;
- for (i = 0, j = 1; j < nOrigPts; i++, j++) {
- Point2d p = origPts[i];
- Point2d q = origPts[j];
-
- double d = hypot(q.x - p.x, q.y - p.y);
- /* Add the original x-coordinate */
- iPts[count].x = (double)i;
- iPts[count].y = 0.0;
-
- /* Include the starting offset of the point in the offset array */
- map[count] = mapPtr->map[i];
- count++;
-
- /* Is any part of the interval (line segment) in the plotting
- * area? */
-
- if (lineRectClip(&exts, &p, &q)) {
- double dp, dq;
-
- /* Distance of original point to p. */
- dp = hypot(p.x - origPts[i].x, p.y - origPts[i].y);
- /* Distance of original point to q. */
- dq = hypot(q.x - origPts[i].x, q.y - origPts[i].y);
- dp += 2.0;
- while(dp <= dq) {
- /* Point is indicated by its interval and parameter t. */
- iPts[count].x = (double)i;
- iPts[count].y = dp / d;
- map[count] = mapPtr->map[i];
- count++;
- dp += 2.0;
- }
- }
- }
- iPts[count].x = (double)i;
- iPts[count].y = 0.0;
- map[count] = mapPtr->map[i];
- count++;
- niPts = count;
- int result = 0;
- if (smooth_ == CUBIC)
- result = naturalParametricSpline(origPts, nOrigPts, &exts, 0, iPts, niPts);
- else if (smooth_ == CATROM)
- result = catromParametricSpline(origPts, nOrigPts, iPts, niPts);
-
- // The spline interpolation failed. We will fall back to the current
- // coordinates and do no smoothing (standard line segments)
- if (!result) {
- smooth_ = LINEAR;
- delete [] iPts;
- delete [] map;
- }
- else {
- delete [] mapPtr->map;
- mapPtr->map = map;
- delete [] mapPtr->screenPts;
- mapPtr->screenPts = iPts;
- mapPtr->nScreenPts = niPts;
- }
-}
-
-void LineElement::mapSymbols(MapInfo *mapPtr)
-{
- Point2d* points = new Point2d[mapPtr->nScreenPts];
- int *map = new int[mapPtr->nScreenPts];
-
- Region2d exts;
- graphPtr_->extents(&exts);
-
- Point2d *pp;
- int count = 0;
- int i;
- for (pp=mapPtr->screenPts, i=0; i<mapPtr->nScreenPts; i++, pp++) {
- if (PointInRegion(&exts, pp->x, pp->y)) {
- points[count].x = pp->x;
- points[count].y = pp->y;
- map[count] = mapPtr->map[i];
- count++;
- }
- }
- symbolPts_.points = points;
- symbolPts_.length = count;
- symbolPts_.map = map;
-}
-
-void LineElement::mapActiveSymbols()
-{
- LineElementOptions* ops = (LineElementOptions*)ops_;
-
- delete [] activePts_.points;
- activePts_.points = NULL;
- delete [] activePts_.map;
- activePts_.map = NULL;
-
- Region2d exts;
- graphPtr_->extents(&exts);
-
- Point2d *points = new Point2d[nActiveIndices_];
- int* map = new int[nActiveIndices_];
- int np = NUMBEROFPOINTS(ops);
- int count = 0;
- if (ops->coords.x && ops->coords.y) {
- for (int ii=0; ii<nActiveIndices_; ii++) {
- int iPoint = activeIndices_[ii];
- if (iPoint >= np)
- continue;
-
- double x = ops->coords.x->values_[iPoint];
- double y = ops->coords.y->values_[iPoint];
- points[count] = graphPtr_->map2D(x, y, ops->xAxis, ops->yAxis);
- map[count] = iPoint;
- if (PointInRegion(&exts, points[count].x, points[count].y)) {
- count++;
- }
- }
- }
-
- if (count > 0) {
- activePts_.points = points;
- activePts_.map = map;
- }
- else {
- delete [] points;
- delete [] map;
- }
- activePts_.length = count;
-}
-
-void LineElement::mergePens(LineStyle **styleMap)
-{
- LineElementOptions* ops = (LineElementOptions*)ops_;
-
- if (Chain_GetLength(ops->stylePalette) < 2) {
- ChainLink* link = Chain_FirstLink(ops->stylePalette);
- LineStyle *stylePtr = (LineStyle*)Chain_GetValue(link);
- stylePtr->symbolPts.length = symbolPts_.length;
- stylePtr->symbolPts.points = symbolPts_.points;
- stylePtr->xeb.length = xeb_.length;
- stylePtr->xeb.segments = xeb_.segments;
- stylePtr->yeb.length = yeb_.length;
- stylePtr->yeb.segments = yeb_.segments;
- return;
- }
-
- if (symbolPts_.length > 0) {
- Point2d* points = new Point2d[symbolPts_.length];
- int* map = new int[symbolPts_.length];
- Point2d *pp = points;
- int* ip = map;
- for (ChainLink* link = Chain_FirstLink(ops->stylePalette); link;
- link = Chain_NextLink(link)) {
- LineStyle *stylePtr = (LineStyle*)Chain_GetValue(link);
- stylePtr->symbolPts.points = pp;
- for (int ii=0; ii<symbolPts_.length; ii++) {
- int iData = symbolPts_.map[ii];
- if (styleMap[iData] == stylePtr) {
- *pp++ = symbolPts_.points[ii];
- *ip++ = iData;
- }
- }
- stylePtr->symbolPts.length = pp - stylePtr->symbolPts.points;
- }
- delete [] symbolPts_.points;
- symbolPts_.points = points;
- delete [] symbolPts_.map;
- symbolPts_.map = map;
- }
-
- if (xeb_.length > 0) {
- Segment2d* segments = new Segment2d[xeb_.length];
- Segment2d *sp = segments;
- int* map = new int[xeb_.length];
- int* ip = map;
- for (ChainLink* link = Chain_FirstLink(ops->stylePalette); link;
- link = Chain_NextLink(link)) {
- LineStyle *stylePtr = (LineStyle*)Chain_GetValue(link);
- stylePtr->xeb.segments = sp;
- for (int ii=0; ii<xeb_.length; ii++) {
- int iData = xeb_.map[ii];
- if (styleMap[iData] == stylePtr) {
- *sp++ = xeb_.segments[ii];
- *ip++ = iData;
- }
- }
- stylePtr->xeb.length = sp - stylePtr->xeb.segments;
- }
- delete [] xeb_.segments;
- xeb_.segments = segments;
- delete [] xeb_.map;
- xeb_.map = map;
- }
-
- if (yeb_.length > 0) {
- Segment2d* segments = new Segment2d[yeb_.length];
- Segment2d* sp = segments;
- int* map = new int [yeb_.length];
- int* ip = map;
- for (ChainLink* link = Chain_FirstLink(ops->stylePalette); link;
- link = Chain_NextLink(link)) {
- LineStyle *stylePtr = (LineStyle*)Chain_GetValue(link);
- stylePtr->yeb.segments = sp;
- for (int ii=0; ii<yeb_.length; ii++) {
- int iData = yeb_.map[ii];
- if (styleMap[iData] == stylePtr) {
- *sp++ = yeb_.segments[ii];
- *ip++ = iData;
- }
- }
- stylePtr->yeb.length = sp - stylePtr->yeb.segments;
- }
- delete [] yeb_.segments;
- yeb_.segments = segments;
- delete [] yeb_.map;
- yeb_.map = map;
- }
-}
-
-void LineElement::saveTrace(int start, int length, MapInfo* mapPtr)
-{
- bltTrace* tracePtr = new bltTrace;
- Point2d* screenPts = new Point2d[length];
- int* map = new int[length];
-
- // Copy the screen coordinates of the trace into the point array
- if (mapPtr->map) {
- for (int ii=0, jj=start; ii<length; ii++, jj++) {
- screenPts[ii].x = mapPtr->screenPts[jj].x;
- screenPts[ii].y = mapPtr->screenPts[jj].y;
- map[ii] = mapPtr->map[jj];
- }
- }
- else {
- for (int ii=0, jj=start; ii<length; ii++, jj++) {
- screenPts[ii].x = mapPtr->screenPts[jj].x;
- screenPts[ii].y = mapPtr->screenPts[jj].y;
- map[ii] = jj;
- }
- }
- tracePtr->screenPts.length = length;
- tracePtr->screenPts.points = screenPts;
- tracePtr->screenPts.map = map;
- tracePtr->start = start;
- if (traces_ == NULL)
- traces_ = new Chain();
-
- traces_->append(tracePtr);
-}
-
-void LineElement::freeTraces()
-{
- for (ChainLink* link = Chain_FirstLink(traces_); link;
- link = Chain_NextLink(link)) {
- bltTrace* tracePtr = (bltTrace*)Chain_GetValue(link);
- delete [] tracePtr->screenPts.map;
- delete [] tracePtr->screenPts.points;
- delete tracePtr;
- }
- delete traces_;
- traces_ = NULL;
-}
-
-void LineElement::mapTraces(MapInfo *mapPtr)
-{
- LineElementOptions* ops = (LineElementOptions*)ops_;
-
- Region2d exts;
- graphPtr_->extents(&exts);
-
- int count = 1;
- Point2d* p = mapPtr->screenPts;
- Point2d* q = p + 1;
-
- int start;
- int ii;
- for (ii=1; ii<mapPtr->nScreenPts; ii++, p++, q++) {
- // Save the coordinates of the last point before clipping.
- Point2d originalq = *q;
- int broken = BROKEN_TRACE(ops->penDir, p->x, q->x);
- LineRectClipResult clipresult = lineRectClip(&exts, p, q);
-
- if (broken || clipresult == CLIP_OUTSIDE) {
- // The last line segment is either totally clipped by the plotting
- // area or the x-direction is wrong, breaking the trace. Either
- // way, save information about the last trace (if one exists),
- // discarding the current line segment
- if (count > 1) {
- start = ii - count;
- saveTrace(start, count, mapPtr);
- count = 1;
- }
- }
- else {
- // Add the point to the trace
- count++;
-
- // If the last point is clipped, this means that the trace is
- // broken after this point. Restore the original coordinate
- // (before clipping) after saving the trace.
- if (clipresult & CLIP_Q) {
- start = ii - (count - 1);
- saveTrace(start, count, mapPtr);
- mapPtr->screenPts[ii] = originalq;
- count = 1;
- }
- }
- }
- if (count > 1) {
- start = ii - count;
- saveTrace(start, count, mapPtr);
- }
-}
-
-void LineElement::mapFillArea(MapInfo *mapPtr)
-{
- LineElementOptions* ops = (LineElementOptions*)ops_;
- GraphOptions* gops = (GraphOptions*)graphPtr_->ops_;
-
- if (fillPts_) {
- delete [] fillPts_;
- fillPts_ = NULL;
- nFillPts_ = 0;
- }
- if (mapPtr->nScreenPts < 3)
- return;
-
- int np = mapPtr->nScreenPts + 3;
- Region2d exts;
- graphPtr_->extents(&exts);
-
- Point2d* origPts = new Point2d[np];
- if (gops->inverted) {
- int i;
- double minX = (double)ops->yAxis->screenMin_;
- for (i = 0; i < mapPtr->nScreenPts; i++) {
- origPts[i].x = mapPtr->screenPts[i].x + 1;
- origPts[i].y = mapPtr->screenPts[i].y;
- if (origPts[i].x < minX) {
- minX = origPts[i].x;
- }
- }
- // Add edges to make the polygon fill to the bottom of plotting window
- origPts[i].x = minX;
- origPts[i].y = origPts[i - 1].y;
- i++;
- origPts[i].x = minX;
- origPts[i].y = origPts[0].y;
- i++;
- origPts[i] = origPts[0];
- }
- else {
- int i;
- double maxY = (double)ops->yAxis->bottom_;
- for (i = 0; i < mapPtr->nScreenPts; i++) {
- origPts[i].x = mapPtr->screenPts[i].x + 1;
- origPts[i].y = mapPtr->screenPts[i].y;
- if (origPts[i].y > maxY) {
- maxY = origPts[i].y;
- }
- }
- // Add edges to extend the fill polygon to the bottom of plotting window
- origPts[i].x = origPts[i - 1].x;
- origPts[i].y = maxY;
- i++;
- origPts[i].x = origPts[0].x;
- origPts[i].y = maxY;
- i++;
- origPts[i] = origPts[0];
- }
-
- Point2d *clipPts = new Point2d[np * 3];
- np = polyRectClip(&exts, origPts, np - 1, clipPts);
-
- delete [] origPts;
- if (np < 3)
- delete [] clipPts;
- else {
- fillPts_ = clipPts;
- nFillPts_ = np;
- }
-}
-
-void LineElement::reset()
-{
- LineElementOptions* ops = (LineElementOptions*)ops_;
-
- freeTraces();
-
- for (ChainLink* link = Chain_FirstLink(ops->stylePalette); link;
- link = Chain_NextLink(link)) {
- LineStyle *stylePtr = (LineStyle*)Chain_GetValue(link);
- stylePtr->symbolPts.length = 0;
- stylePtr->xeb.length = 0;
- stylePtr->yeb.length = 0;
- }
-
- delete [] symbolPts_.points;
- symbolPts_.points = NULL;
-
- delete [] symbolPts_.map;
- symbolPts_.map = NULL;
- symbolPts_.length = 0;
-
- delete [] activePts_.points;
- activePts_.points = NULL;
- activePts_.length = 0;
-
- delete [] activePts_.map;
- activePts_.map = 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;
-}
-
-void LineElement::mapErrorBars(LineStyle **styleMap)
-{
- LineElementOptions* ops = (LineElementOptions*)ops_;
-
- Region2d exts;
- graphPtr_->extents(&exts);
-
- int nn =0;
- int np = NUMBEROFPOINTS(ops);
- if (ops->coords.x && ops->coords.y) {
- if (ops->xError && (ops->xError->nValues() > 0))
- nn = MIN(ops->xError->nValues(), np);
- else
- if (ops->xHigh && ops->xLow)
- nn = MIN3(ops->xHigh->nValues(), ops->xLow->nValues(), np);
- }
-
- if (nn) {
- Segment2d* errorBars = new Segment2d[nn * 3];
- Segment2d* segPtr = errorBars;
- int* errorToData = new int[nn * 3];
- int* indexPtr = errorToData;
-
- for (int ii=0; ii<nn; ii++) {
- double x = ops->coords.x->values_[ii];
- double y = ops->coords.y->values_[ii];
- LineStyle* stylePtr = styleMap[ii];
-
- if ((isfinite(x)) && (isfinite(y))) {
- double high;
- double low;
- if (ops->xError && 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(&exts, &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(&exts, &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(&exts, &segPtr->p, &segPtr->q)) {
- segPtr++;
- *indexPtr++ = ii;
- }
- }
- }
- }
- xeb_.segments = errorBars;
- xeb_.length = segPtr - errorBars;
- xeb_.map = errorToData;
- }
-
- nn =0;
- if (ops->coords.x && ops->coords.y) {
- if (ops->yError && (ops->yError->nValues() > 0))
- nn = MIN(ops->yError->nValues(), np);
- else
- if (ops->yHigh && ops->yLow)
- nn = MIN3(ops->yHigh->nValues(), ops->yLow->nValues(), np);
- }
-
- if (nn) {
- Segment2d* errorBars = new Segment2d[nn * 3];
- Segment2d* segPtr = errorBars;
- int* errorToData = new int[nn * 3];
- int* indexPtr = errorToData;
-
- for (int ii=0; ii<nn; ii++) {
- double x = ops->coords.x->values_[ii];
- double y = ops->coords.y->values_[ii];
- LineStyle* stylePtr = styleMap[ii];
-
- if ((isfinite(x)) && (isfinite(y))) {
- double high;
- double low;
- if (ops->yError && 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(&exts, &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(&exts, &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(&exts, &segPtr->p, &segPtr->q)) {
- segPtr++;
- *indexPtr++ = ii;
- }
- }
- }
- }
- yeb_.segments = errorBars;
- yeb_.length = segPtr - errorBars;
- yeb_.map = errorToData;
- }
-}
-
-int LineElement::closestTrace()
-{
- LineElementOptions* ops = (LineElementOptions*)ops_;
- GraphOptions* gops = (GraphOptions*)graphPtr_->ops_;
- ClosestSearch* searchPtr = &gops->search;
-
- Point2d closest;
-
- int iClose = -1;
- double dMin = searchPtr->dist;
- closest.x = closest.y = 0;
- for (ChainLink *link=Chain_FirstLink(traces_); link;
- link = Chain_NextLink(link)) {
- bltTrace *tracePtr = (bltTrace*)Chain_GetValue(link);
- for (Point2d *p=tracePtr->screenPts.points,
- *pend=p + (tracePtr->screenPts.length - 1); p<pend; p++) {
- Point2d b;
- double d;
- if (searchPtr->along == SEARCH_X)
- d = distanceToX(searchPtr->x, searchPtr->y, p, p + 1, &b);
- else if (searchPtr->along == SEARCH_Y)
- d = distanceToY(searchPtr->x, searchPtr->y, p, p + 1, &b);
- else
- d = distanceToLine(searchPtr->x, searchPtr->y, p, p + 1, &b);
-
- if (d < dMin) {
- closest = b;
- iClose = tracePtr->screenPts.map[p-tracePtr->screenPts.points];
- dMin = d;
- }
- }
- }
- if (dMin < searchPtr->dist) {
- searchPtr->dist = dMin;
- searchPtr->elemPtr = (Element*)this;
- searchPtr->index = iClose;
- searchPtr->point = graphPtr_->invMap2D(closest.x, closest.y,
- ops->xAxis, ops->yAxis);
- return 1;
- }
-
- return 0;
-}
-
-void LineElement::closestPoint(ClosestSearch *searchPtr)
-{
- LineElementOptions* ops = (LineElementOptions*)ops_;
-
- double dMin = searchPtr->dist;
- int iClose = 0;
-
- // Instead of testing each data point in graph coordinates, look at the
- // array of mapped screen coordinates. The advantages are
- // 1) only examine points that are visible (unclipped), and
- // 2) the computed distance is already in screen coordinates.
- int count =0;
- for (Point2d *pp = symbolPts_.points; count < symbolPts_.length;
- count++, pp++) {
- double dx = (double)abs(searchPtr->x - pp->x);
- double dy = (double)abs(searchPtr->y - pp->y);
- double d;
- if (searchPtr->along == SEARCH_BOTH)
- d = hypot(dx, dy);
- else if (searchPtr->along == SEARCH_X)
- d = dx;
- else if (searchPtr->along == SEARCH_Y)
- d = dy;
- else
- continue;
-
- if (d < dMin) {
- iClose = symbolPts_.map[count];
- dMin = d;
- }
- }
- if (dMin < searchPtr->dist) {
- searchPtr->elemPtr = (Element*)this;
- searchPtr->dist = dMin;
- searchPtr->index = iClose;
- searchPtr->point.x = ops->coords.x->values_[iClose];
- searchPtr->point.y = ops->coords.y->values_[iClose];
- }
-}
-
-void LineElement::drawCircle(Display *display, Drawable drawable,
- LinePen* penPtr,
- int nSymbolPts, Point2d *symbolPts, int radius)
-{
- LinePenOptions* penOps = (LinePenOptions*)penPtr->ops();
-
- int count = 0;
- int s = radius + radius;
- XArc* arcs = new XArc[nSymbolPts];
- XArc *ap = arcs;
- for (Point2d *pp=symbolPts, *pend=pp+nSymbolPts; pp<pend; pp++) {
- if (DRAW_SYMBOL()) {
- ap->x = (short)(pp->x - radius);
- ap->y = (short)(pp->y - radius);
- ap->width = (short)s;
- ap->height = (short)s;
- ap->angle1 = 0;
- ap->angle2 = 23040;
- ap++;
- count++;
- }
- symbolCounter_++;
- }
-
- for (XArc *ap=arcs, *aend=ap+count; ap<aend; ap++) {
- if (penOps->symbol.fillGC)
- XFillArc(display, drawable, penOps->symbol.fillGC,
- ap->x, ap->y, ap->width, ap->height, ap->angle1, ap->angle2);
-
- if (penOps->symbol.outlineWidth > 0)
- XDrawArc(display, drawable, penOps->symbol.outlineGC,
- ap->x, ap->y, ap->width, ap->height, ap->angle1, ap->angle2);
- }
-
- delete [] arcs;
-}
-
-void LineElement::drawSquare(Display *display, Drawable drawable,
- LinePen* penPtr,
- int nSymbolPts, Point2d *symbolPts, int r)
-{
- LinePenOptions* penOps = (LinePenOptions*)penPtr->ops();
-
- int s = r + r;
- int count =0;
- Rectangle* rectangles = new Rectangle[nSymbolPts];
- Rectangle* rp=rectangles;
- for (Point2d *pp=symbolPts, *pend=pp+nSymbolPts; pp<pend; pp++) {
- if (DRAW_SYMBOL()) {
- rp->x = (int)pp->x - r;
- rp->y = (int)pp->y - r;
- rp->width = s;
- rp->height = s;
- rp++;
- count++;
- }
- symbolCounter_++;
- }
-
- for (Rectangle *rp=rectangles, *rend=rp+count; rp<rend; rp ++) {
- if (penOps->symbol.fillGC)
- XFillRectangle(display, drawable, penOps->symbol.fillGC,
- rp->x, rp->y, rp->width, rp->height);
-
- if (penOps->symbol.outlineWidth > 0)
- XDrawRectangle(display, drawable, penOps->symbol.outlineGC,
- rp->x, rp->y, rp->width, rp->height);
- }
-
- delete [] rectangles;
-}
-
-void LineElement::drawSCross(Display* display, Drawable drawable,
- LinePen* penPtr,
- int nSymbolPts, Point2d* symbolPts, int r2)
-{
- LinePenOptions* penOps = (LinePenOptions*)penPtr->ops();
-
- Point pattern[4];
- if (penOps->symbol.type == SYMBOL_SCROSS) {
- r2 = (int)(r2 * M_SQRT1_2);
- pattern[3].y = pattern[2].x = pattern[0].x = pattern[0].y = -r2;
- pattern[3].x = pattern[2].y = pattern[1].y = pattern[1].x = r2;
- }
- else {
- pattern[0].y = pattern[1].y = pattern[2].x = pattern[3].x = 0;
- pattern[0].x = pattern[2].y = -r2;
- pattern[1].x = pattern[3].y = r2;
- }
-
- for (Point2d *pp=symbolPts, *endp=pp+nSymbolPts; pp<endp; pp++) {
- if (DRAW_SYMBOL()) {
- int rndx = (int)pp->x;
- int rndy = (int)pp->y;
- XDrawLine(graphPtr_->display_, drawable, penOps->symbol.outlineGC,
- pattern[0].x + rndx, pattern[0].y + rndy,
- pattern[1].x + rndx, pattern[1].y + rndy);
- XDrawLine(graphPtr_->display_, drawable, penOps->symbol.outlineGC,
- pattern[2].x + rndx, pattern[2].y + rndy,
- pattern[3].x + rndx, pattern[3].y + rndy);
- }
- }
-}
-
-void LineElement::drawCross(Display *display, Drawable drawable,
- LinePen* penPtr,
- int nSymbolPts, Point2d *symbolPts, int r2)
-{
- LinePenOptions* penOps = (LinePenOptions*)penPtr->ops();
-
- /*
- * 2 3 The plus/cross symbol is a closed polygon
- * of 12 points. The diagram to the left
- * 0,12 1 4 5 represents the positions of the points
- * x,y which are computed below. The extra
- * 11 10 7 6 (thirteenth) point connects the first and
- * last points.
- * 9 8
- */
- int d = (r2 / 3);
- Point pattern[13];
- pattern[0].x = pattern[11].x = pattern[12].x = -r2;
- pattern[2].x = pattern[1].x = pattern[10].x = pattern[9].x = -d;
- pattern[3].x = pattern[4].x = pattern[7].x = pattern[8].x = d;
- pattern[5].x = pattern[6].x = r2;
- pattern[2].y = pattern[3].y = -r2;
- pattern[0].y = pattern[1].y = pattern[4].y = pattern[5].y =
- pattern[12].y = -d;
- pattern[11].y = pattern[10].y = pattern[7].y = pattern[6].y = d;
- pattern[9].y = pattern[8].y = r2;
-
- if (penOps->symbol.type == SYMBOL_CROSS) {
- // For the cross symbol, rotate the points by 45 degrees
- for (int ii=0; ii<12; ii++) {
- double dx = (double)pattern[ii].x * M_SQRT1_2;
- double dy = (double)pattern[ii].y * M_SQRT1_2;
- pattern[ii].x = (int)(dx - dy);
- pattern[ii].y = (int)(dx + dy);
- }
- pattern[12] = pattern[0];
- }
-
- int count = 0;
- XPoint* polygon = new XPoint[nSymbolPts*13];
- XPoint* xpp = polygon;
- for (Point2d *pp = symbolPts, *endp = pp + nSymbolPts; pp < endp; pp++) {
- if (DRAW_SYMBOL()) {
- int rndx = (int)pp->x;
- int rndy = (int)pp->y;
- for (int ii=0; ii<13; ii++) {
- xpp->x = (short)(pattern[ii].x + rndx);
- xpp->y = (short)(pattern[ii].y + rndy);
- xpp++;
- }
- count++;
- }
- symbolCounter_++;
- }
-
- if (penOps->symbol.fillGC) {
- XPoint* xpp = polygon;
- for (int ii=0; ii<count; ii++, xpp += 13)
- XFillPolygon(graphPtr_->display_, drawable,
- penOps->symbol.fillGC, xpp, 13, Complex,
- CoordModeOrigin);
- }
-
- if (penOps->symbol.outlineWidth > 0) {
- XPoint*xpp = polygon;
- for (int ii=0; ii<count; ii++, xpp += 13)
- XDrawLines(graphPtr_->display_, drawable,
- penOps->symbol.outlineGC, xpp, 13, CoordModeOrigin);
- }
-
- delete [] polygon;
-}
-
-void LineElement::drawDiamond(Display *display, Drawable drawable,
- LinePen* penPtr,
- int nSymbolPts, Point2d *symbolPts, int r1)
-{
- LinePenOptions* penOps = (LinePenOptions*)penPtr->ops();
-
- /*
- * The plus symbol is a closed polygon
- * 1 of 4 points. The diagram to the left
- * represents the positions of the points
- * 0,4 x,y 2 which are computed below. The extra
- * (fifth) point connects the first and
- * 3 last points.
- */
- Point pattern[5];
- pattern[1].y = pattern[0].x = -r1;
- pattern[2].y = pattern[3].x = pattern[0].y = pattern[1].x = 0;
- pattern[3].y = pattern[2].x = r1;
- pattern[4] = pattern[0];
-
- int count = 0;
- XPoint* polygon = new XPoint[nSymbolPts*5];
- XPoint* xpp = polygon;
- for (Point2d *pp = symbolPts, *endp = pp + nSymbolPts; pp < endp; pp++) {
- if (DRAW_SYMBOL()) {
- int rndx = (int)pp->x;
- int rndy = (int)pp->y;
- for (int ii=0; ii<5; ii++) {
- xpp->x = (short)(pattern[ii].x + rndx);
- xpp->y = (short)(pattern[ii].y + rndy);
- xpp++;
- }
- count++;
- }
- symbolCounter_++;
- }
-
- if (penOps->symbol.fillGC) {
- XPoint* xpp = polygon;
- for (int ii=0; ii<count; ii++, xpp += 5)
- XFillPolygon(graphPtr_->display_, drawable,
- penOps->symbol.fillGC, xpp, 5, Convex, CoordModeOrigin);
- }
-
- if (penOps->symbol.outlineWidth > 0) {
- XPoint* xpp = polygon;
- for (int ii=0; ii<count; ii++, xpp += 5)
- XDrawLines(graphPtr_->display_, drawable,
- penOps->symbol.outlineGC, xpp, 5, CoordModeOrigin);
- }
-
- delete [] polygon;
-}
-
-#define B_RATIO 1.3467736870885982
-#define TAN30 0.57735026918962573
-#define COS30 0.86602540378443871
-void LineElement::drawArrow(Display *display, Drawable drawable,
- LinePen* penPtr,
- int nSymbolPts, Point2d *symbolPts, int size)
-{
- LinePenOptions* penOps = (LinePenOptions*)penPtr->ops();
-
- double b = size * B_RATIO * 0.7 * 0.5;
- short b2 = (short)b;
- short h2 = (short)(TAN30 * b);
- short h1 = (short)(b / COS30);
- /*
- * The triangle symbol is a closed polygon
- * 0,3 of 3 points. The diagram to the left
- * represents the positions of the points
- * x,y which are computed below. The extra
- * (fourth) point connects the first and
- * 2 1 last points.
- */
-
- Point pattern[4];
- if (penOps->symbol.type == SYMBOL_ARROW) {
- pattern[3].x = pattern[0].x = 0;
- pattern[3].y = pattern[0].y = h1;
- pattern[1].x = b2;
- pattern[2].y = pattern[1].y = -h2;
- pattern[2].x = -b2;
- } else {
- pattern[3].x = pattern[0].x = 0;
- pattern[3].y = pattern[0].y = -h1;
- pattern[1].x = b2;
- pattern[2].y = pattern[1].y = h2;
- pattern[2].x = -b2;
- }
-
- int count = 0;
- XPoint* polygon = new XPoint[nSymbolPts*4];
- XPoint* xpp = polygon;
- for (Point2d *pp = symbolPts, *endp = pp + nSymbolPts; pp < endp; pp++) {
- if (DRAW_SYMBOL()) {
- int rndx = (int)pp->x;
- int rndy = (int)pp->y;
- for (int ii=0; ii<4; ii++) {
- xpp->x = (short)(pattern[ii].x + rndx);
- xpp->y = (short)(pattern[ii].y + rndy);
- xpp++;
- }
- count++;
- }
- symbolCounter_++;
- }
-
- if (penOps->symbol.fillGC) {
- XPoint* xpp = polygon;
- for (int ii=0; ii<count; ii++, xpp += 4)
- XFillPolygon(graphPtr_->display_, drawable,
- penOps->symbol.fillGC, xpp, 4, Convex, CoordModeOrigin);
- }
-
- if (penOps->symbol.outlineWidth > 0) {
- XPoint* xpp = polygon;
- for (int ii=0; ii<count; ii++, xpp += 4)
- XDrawLines(graphPtr_->display_, drawable,
- penOps->symbol.outlineGC, xpp, 4, CoordModeOrigin);
- }
-
- delete [] polygon;
-}
-
-#define S_RATIO 0.886226925452758
-void LineElement::drawSymbols(Drawable drawable, LinePen* penPtr, int size,
- int nSymbolPts, Point2d* symbolPts)
-{
- LinePenOptions* penOps = (LinePenOptions*)penPtr->ops();
-
- if (size < 3) {
- if (penOps->symbol.fillGC) {
- for (Point2d *pp = symbolPts, *endp = pp + nSymbolPts; pp < endp; pp++)
- XDrawLine(graphPtr_->display_, drawable, penOps->symbol.fillGC,
- (int)pp->x, (int)pp->y, (int)pp->x+1, (int)pp->y+1);
- }
- return;
- }
-
- int r1 = (int)ceil(size * 0.5);
- int r2 = (int)ceil(size * S_RATIO * 0.5);
-
- switch (penOps->symbol.type) {
- case SYMBOL_NONE:
- break;
- case SYMBOL_SQUARE:
- drawSquare(graphPtr_->display_, drawable, penPtr, nSymbolPts,symbolPts,r2);
- break;
- case SYMBOL_CIRCLE:
- drawCircle(graphPtr_->display_, drawable, penPtr, nSymbolPts,symbolPts,r1);
- break;
- case SYMBOL_SPLUS:
- case SYMBOL_SCROSS:
- drawSCross(graphPtr_->display_, drawable, penPtr, nSymbolPts,symbolPts,r2);
- break;
- case SYMBOL_PLUS:
- case SYMBOL_CROSS:
- drawCross(graphPtr_->display_, drawable, penPtr, nSymbolPts,symbolPts,r2);
- break;
- case SYMBOL_DIAMOND:
- drawDiamond(graphPtr_->display_, drawable, penPtr, nSymbolPts,symbolPts,r1);
- break;
- case SYMBOL_TRIANGLE:
- case SYMBOL_ARROW:
- drawArrow(graphPtr_->display_, drawable, penPtr, nSymbolPts,symbolPts,size);
- break;
- }
-}
-
-void LineElement::drawTraces(Drawable drawable, LinePen* penPtr)
-{
- for (ChainLink* link = Chain_FirstLink(traces_); link;
- link = Chain_NextLink(link)) {
- bltTrace* tracePtr = (bltTrace*)Chain_GetValue(link);
-
- int count = tracePtr->screenPts.length;
- XPoint* points = new XPoint[count];
- XPoint*xpp = points;
- for (int ii=0; ii<count; ii++, xpp++) {
- xpp->x = (short)tracePtr->screenPts.points[ii].x;
- xpp->y = (short)tracePtr->screenPts.points[ii].y;
- }
- XDrawLines(graphPtr_->display_, drawable, penPtr->traceGC_, points,
- count, CoordModeOrigin);
- delete [] points;
- }
-}
-
-void LineElement::drawValues(Drawable drawable, LinePen* penPtr,
- int length, Point2d *points, int *map)
-{
- LineElementOptions* ops = (LineElementOptions*)ops_;
- LinePenOptions* pops = (LinePenOptions*)penPtr->ops();
-
- char string[TCL_DOUBLE_SPACE * 2 + 2];
- const char* fmt = pops->valueFormat;
- if (fmt == NULL)
- fmt = "%g";
- TextStyle ts(graphPtr_, &pops->valueStyle);
-
- double* xval = ops->coords.x->values_;
- double* yval = ops->coords.y->values_;
- int count = 0;
-
- for (Point2d *pp = points, *endp = points + length; pp < endp; pp++) {
- double x = xval[map[count]];
- double y = yval[map[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);
- }
-
- ts.drawText(drawable, string, pp->x, pp->y);
- }
-}
-
-void LineElement::printSymbols(PSOutput* psPtr, LinePen* penPtr, int size,
- int nSymbolPts, Point2d *symbolPts)
-{
- LinePenOptions* pops = (LinePenOptions*)penPtr->ops();
-
- double symbolSize;
-
- // Set line and foreground attributes
- XColor* fillColor = pops->symbol.fillColor;
- if (!fillColor)
- fillColor = pops->traceColor;
-
- XColor* outlineColor = pops->symbol.outlineColor;
- if (!outlineColor)
- outlineColor = pops->traceColor;
-
- if (pops->symbol.type == SYMBOL_NONE)
- psPtr->setLineAttributes(pops->traceColor, pops->traceWidth + 2,
- &pops->traceDashes, CapButt, JoinMiter);
- else {
- psPtr->setLineWidth(pops->symbol.outlineWidth);
- psPtr->setDashes(NULL);
- }
-
- // build DrawSymbolProc
- psPtr->append("\n/DrawSymbolProc {\n");
- switch (pops->symbol.type) {
- case SYMBOL_NONE:
- break;
- default:
- psPtr->append(" ");
- psPtr->setBackground(fillColor);
- psPtr->append(" gsave fill grestore\n");
-
- if (pops->symbol.outlineWidth > 0) {
- psPtr->append(" ");
- psPtr->setForeground(outlineColor);
- psPtr->append(" stroke\n");
- }
- break;
- }
- psPtr->append("} def\n\n");
-
- // set size
- symbolSize = (double)size;
- switch (pops->symbol.type) {
- case SYMBOL_SQUARE:
- case SYMBOL_CROSS:
- case SYMBOL_PLUS:
- case SYMBOL_SCROSS:
- case SYMBOL_SPLUS:
- symbolSize = (double)size * S_RATIO;
- break;
- case SYMBOL_TRIANGLE:
- case SYMBOL_ARROW:
- symbolSize = (double)size * 0.7;
- break;
- case SYMBOL_DIAMOND:
- symbolSize = (double)size * M_SQRT1_2;
- break;
-
- default:
- break;
- }
-
- int count =0;
- for (Point2d *pp=symbolPts, *endp=symbolPts + nSymbolPts; pp < endp; pp++) {
- if (DRAW_SYMBOL()) {
- psPtr->format("%g %g %g %s\n", pp->x, pp->y, symbolSize,
- symbolMacros[pops->symbol.type]);
- count++;
- }
- symbolCounter_++;
- }
-}
-
-void LineElement::setLineAttributes(PSOutput* psPtr, LinePen* penPtr)
-{
- LinePenOptions* pops = (LinePenOptions*)penPtr->ops();
-
- psPtr->setLineAttributes(pops->traceColor, pops->traceWidth,
- &pops->traceDashes, CapButt, JoinMiter);
-
- if ((LineIsDashed(pops->traceDashes)) &&
- (pops->traceOffColor)) {
- psPtr->append("/DashesProc {\n gsave\n ");
- psPtr->setBackground(pops->traceOffColor);
- psPtr->append(" ");
- psPtr->setDashes(NULL);
- psPtr->append("stroke\n grestore\n} def\n");
- } else {
- psPtr->append("/DashesProc {} def\n");
- }
-}
-
-void LineElement::printTraces(PSOutput* psPtr, LinePen* penPtr)
-{
- setLineAttributes(psPtr, penPtr);
- for (ChainLink* link = Chain_FirstLink(traces_); link;
- link = Chain_NextLink(link)) {
- bltTrace *tracePtr = (bltTrace*)Chain_GetValue(link);
- if (tracePtr->screenPts.length > 0) {
- psPtr->append("% start trace\n");
- psPtr->printMaxPolyline(tracePtr->screenPts.points,
- tracePtr->screenPts.length);
- psPtr->append("% end trace\n");
- }
- }
-}
-
-void LineElement::printValues(PSOutput* psPtr, LinePen* penPtr,
- int nSymbolPts, Point2d *symbolPts,
- int *pointToData)
-{
- LineElementOptions* ops = (LineElementOptions*)ops_;
- LinePenOptions* pops = (LinePenOptions*)penPtr->ops();
-
- const char* fmt = pops->valueFormat;
- if (fmt == NULL)
- fmt = "%g";
- TextStyle ts(graphPtr_, &pops->valueStyle);
-
- int count = 0;
- for (Point2d *pp=symbolPts, *endp=symbolPts + nSymbolPts; pp < endp; pp++) {
- double x = ops->coords.x->values_[pointToData[count]];
- double y = ops->coords.y->values_[pointToData[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);
- }
-
- ts.printText(psPtr, string, pp->x, pp->y);
- }
-}
-
-