summaryrefslogtreecommitdiffstats
path: root/tkblt/generic/tkbltGrMarkerLine.C
diff options
context:
space:
mode:
Diffstat (limited to 'tkblt/generic/tkbltGrMarkerLine.C')
-rw-r--r--tkblt/generic/tkbltGrMarkerLine.C298
1 files changed, 298 insertions, 0 deletions
diff --git a/tkblt/generic/tkbltGrMarkerLine.C b/tkblt/generic/tkbltGrMarkerLine.C
new file mode 100644
index 0000000..82c9ab8
--- /dev/null
+++ b/tkblt/generic/tkbltGrMarkerLine.C
@@ -0,0 +1,298 @@
+/*
+ * 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 <cmath>
+
+#include "tkbltGraph.h"
+#include "tkbltGrMarkerLine.h"
+#include "tkbltGrMarkerOption.h"
+#include "tkbltGrMisc.h"
+#include "tkbltGrDef.h"
+#include "tkbltConfig.h"
+#include "tkbltGrPSOutput.h"
+
+using namespace Blt;
+
+#define BOUND(x, lo, hi) (((x) > (hi)) ? (hi) : ((x) < (lo)) ? (lo) : (x))
+
+static Tk_OptionSpec optionSpecs[] = {
+ {TK_OPTION_CUSTOM, "-bindtags", "bindTags", "BindTags",
+ "Line all", -1, Tk_Offset(LineMarkerOptions, tags),
+ TK_OPTION_NULL_OK, &listObjOption, 0},
+ {TK_OPTION_CUSTOM, "-cap", "cap", "Cap",
+ "butt", -1, Tk_Offset(LineMarkerOptions, capStyle),
+ 0, &capStyleObjOption, 0},
+ {TK_OPTION_CUSTOM, "-coords", "coords", "Coords",
+ NULL, -1, Tk_Offset(LineMarkerOptions, worldPts),
+ TK_OPTION_NULL_OK, &coordsObjOption, 0},
+ {TK_OPTION_CUSTOM, "-dashes", "dashes", "Dashes",
+ NULL, -1, Tk_Offset(LineMarkerOptions, dashes),
+ TK_OPTION_NULL_OK, &dashesObjOption, 0},
+ {TK_OPTION_PIXELS, "-dashoffset", "dashOffset", "DashOffset",
+ "0", -1, Tk_Offset(LineMarkerOptions, dashes.offset), 0, NULL, 0},
+ {TK_OPTION_STRING, "-element", "element", "Element",
+ NULL, -1, Tk_Offset(LineMarkerOptions, elemName),
+ TK_OPTION_NULL_OK, NULL, 0},
+ {TK_OPTION_COLOR, "-fill", "fill", "Fill",
+ NULL, -1, Tk_Offset(LineMarkerOptions, fillColor),
+ TK_OPTION_NULL_OK, NULL, 0},
+ {TK_OPTION_CUSTOM, "-join", "join", "Join",
+ "miter", -1, Tk_Offset(LineMarkerOptions, joinStyle),
+ 0, &joinStyleObjOption, 0},
+ {TK_OPTION_PIXELS, "-linewidth", "lineWidth", "LineWidth",
+ "1", -1, Tk_Offset(LineMarkerOptions, lineWidth), 0, NULL, 0},
+ {TK_OPTION_BOOLEAN, "-hide", "hide", "Hide",
+ "no", -1, Tk_Offset(LineMarkerOptions, hide), 0, NULL, 0},
+ {TK_OPTION_CUSTOM, "-mapx", "mapX", "MapX",
+ "x", -1, Tk_Offset(LineMarkerOptions, xAxis), 0, &xAxisObjOption, 0},
+ {TK_OPTION_CUSTOM, "-mapy", "mapY", "MapY",
+ "y", -1, Tk_Offset(LineMarkerOptions, yAxis), 0, &yAxisObjOption, 0},
+ {TK_OPTION_COLOR, "-outline", "outline", "Outline",
+ STD_NORMAL_FOREGROUND, -1, Tk_Offset(LineMarkerOptions, outlineColor),
+ TK_OPTION_NULL_OK, NULL, 0},
+ {TK_OPTION_BOOLEAN, "-under", "under", "Under",
+ "no", -1, Tk_Offset(LineMarkerOptions, drawUnder), 0, NULL, CACHE},
+ {TK_OPTION_PIXELS, "-xoffset", "xOffset", "XOffset",
+ "0", -1, Tk_Offset(LineMarkerOptions, xOffset), 0, NULL, 0},
+ {TK_OPTION_PIXELS, "-yoffset", "yOffset", "YOffset",
+ "0", -1, Tk_Offset(LineMarkerOptions, yOffset), 0, NULL, 0},
+ {TK_OPTION_END, NULL, NULL, NULL, NULL, 0, -1, 0, 0, 0}
+};
+
+LineMarker::LineMarker(Graph* graphPtr, const char* name, Tcl_HashEntry* hPtr)
+ : Marker(graphPtr, name, hPtr)
+{
+ ops_ = (LineMarkerOptions*)calloc(1, sizeof(LineMarkerOptions));
+ optionTable_ = Tk_CreateOptionTable(graphPtr->interp_, optionSpecs);
+
+ gc_ =NULL;
+ segments_ =NULL;
+ nSegments_ =0;
+}
+
+LineMarker::~LineMarker()
+{
+ if (gc_)
+ graphPtr_->freePrivateGC(gc_);
+ delete [] segments_;
+}
+
+int LineMarker::configure()
+{
+ LineMarkerOptions* ops = (LineMarkerOptions*)ops_;
+
+ unsigned long gcMask = (GCLineWidth | GCLineStyle | GCCapStyle | GCJoinStyle);
+ XGCValues gcValues;
+ if (ops->outlineColor) {
+ gcMask |= GCForeground;
+ gcValues.foreground = ops->outlineColor->pixel;
+ }
+ if (ops->fillColor) {
+ gcMask |= GCBackground;
+ gcValues.background = ops->fillColor->pixel;
+ }
+ gcValues.cap_style = ops->capStyle;
+ gcValues.join_style = ops->joinStyle;
+ gcValues.line_width = ops->lineWidth;
+ gcValues.line_style = LineSolid;
+ if (LineIsDashed(ops->dashes)) {
+ gcValues.line_style =
+ (gcMask & GCBackground) ? LineDoubleDash : LineOnOffDash;
+ }
+
+ GC newGC = graphPtr_->getPrivateGC(gcMask, &gcValues);
+ if (gc_)
+ graphPtr_->freePrivateGC(gc_);
+
+ if (LineIsDashed(ops->dashes))
+ graphPtr_->setDashes(newGC, &ops->dashes);
+ gc_ = newGC;
+
+ return TCL_OK;
+}
+
+void LineMarker::draw(Drawable drawable)
+{
+ if (nSegments_ > 0)
+ graphPtr_->drawSegments(drawable, gc_, segments_, nSegments_);
+}
+
+void LineMarker::map()
+{
+ LineMarkerOptions* ops = (LineMarkerOptions*)ops_;
+
+ delete [] segments_;
+ segments_ = NULL;
+ nSegments_ = 0;
+
+ if (!ops->worldPts || (ops->worldPts->num < 2))
+ return;
+
+ Region2d extents;
+ graphPtr_->extents(&extents);
+
+ // Allow twice the number of world coordinates. The line will represented
+ // as series of line segments, not one continous polyline. This is
+ // because clipping against the plot area may chop the line into several
+ // disconnected segments.
+
+ Segment2d* segments = new Segment2d[ops->worldPts->num];
+ Point2d* srcPtr = ops->worldPts->points;
+ Point2d p = mapPoint(srcPtr, ops->xAxis, ops->yAxis);
+ p.x += ops->xOffset;
+ p.y += ops->yOffset;
+
+ Segment2d* segPtr = segments;
+ Point2d* pend;
+ for (srcPtr++, pend = ops->worldPts->points + ops->worldPts->num;
+ srcPtr < pend; srcPtr++) {
+ Point2d next = mapPoint(srcPtr, ops->xAxis, ops->yAxis);
+ next.x += ops->xOffset;
+ next.y += ops->yOffset;
+ Point2d q = next;
+
+ if (lineRectClip(&extents, &p, &q)) {
+ segPtr->p = p;
+ segPtr->q = q;
+ segPtr++;
+ }
+ p = next;
+ }
+ nSegments_ = segPtr - segments;
+ segments_ = segments;
+ clipped_ = (nSegments_ == 0);
+}
+
+int LineMarker::pointIn(Point2d *samplePtr)
+{
+ GraphOptions* gops = (GraphOptions*)graphPtr_->ops_;
+ return pointInSegments(samplePtr, segments_, nSegments_,
+ (double)gops->search.halo);
+}
+
+int LineMarker::pointInSegments(Point2d* samplePtr, Segment2d* segments,
+ int nSegments, double halo)
+{
+ double minDist = DBL_MAX;
+ for (Segment2d *sp = segments, *send = sp + nSegments; sp < send; sp++) {
+ Point2d t = getProjection((int)samplePtr->x, (int)samplePtr->y,
+ &sp->p, &sp->q);
+ double right;
+ double left;
+ if (sp->p.x > sp->q.x) {
+ right = sp->p.x;
+ left = sp->q.x;
+ }
+ else {
+ right = sp->q.x;
+ left = sp->p.x;
+ }
+
+ double top;
+ double bottom;
+ if (sp->p.y > sp->q.y) {
+ bottom = sp->p.y;
+ top = sp->q.y;
+ }
+ else {
+ bottom = sp->q.y;
+ top = sp->p.y;
+ }
+
+ Point2d p;
+ p.x = BOUND(t.x, left, right);
+ p.y = BOUND(t.y, top, bottom);
+
+ double dist = hypot(p.x - samplePtr->x, p.y - samplePtr->y);
+ if (dist < minDist)
+ minDist = dist;
+ }
+
+ return (minDist < halo);
+}
+
+int LineMarker::regionIn(Region2d *extsPtr, int enclosed)
+{
+ LineMarkerOptions* ops = (LineMarkerOptions*)ops_;
+
+ if (!ops->worldPts || ops->worldPts->num < 2)
+ return 0;
+
+ if (enclosed) {
+ for (Point2d *pp = ops->worldPts->points, *pend = pp + ops->worldPts->num;
+ pp < pend; pp++) {
+ Point2d p = mapPoint(pp, ops->xAxis, ops->yAxis);
+ if ((p.x < extsPtr->left) && (p.x > extsPtr->right) &&
+ (p.y < extsPtr->top) && (p.y > extsPtr->bottom)) {
+ return 0;
+ }
+ }
+ return 1;
+ }
+ else {
+ int count = 0;
+ for (Point2d *pp=ops->worldPts->points, *pend=pp+(ops->worldPts->num - 1);
+ pp < pend; pp++) {
+ Point2d p = mapPoint(pp, ops->xAxis, ops->yAxis);
+ Point2d q = mapPoint(pp + 1, ops->xAxis, ops->yAxis);
+ if (lineRectClip(extsPtr, &p, &q))
+ count++;
+ }
+ return (count > 0); /* At least 1 segment passes through
+ * region. */
+ }
+}
+
+void LineMarker::print(PSOutput* psPtr)
+{
+ LineMarkerOptions* ops = (LineMarkerOptions*)ops_;
+
+ if (nSegments_ > 0) {
+ psPtr->setLineAttributes(ops->outlineColor, ops->lineWidth,
+ &ops->dashes, ops->capStyle, ops->joinStyle);
+ if ((LineIsDashed(ops->dashes)) && (ops->fillColor)) {
+ psPtr->append("/DashesProc {\n gsave\n ");
+ psPtr->setBackground(ops->fillColor);
+ psPtr->append(" ");
+ psPtr->setDashes(NULL);
+ psPtr->append("stroke\n");
+ psPtr->append("grestore\n");
+ psPtr->append("} def\n");
+ }
+ else
+ psPtr->append("/DashesProc {} def\n");
+
+ psPtr->printSegments(segments_, nSegments_);
+ }
+}
+
+