summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAdrián Medraño Calvo <adrian@medranocalvo.com>2018-10-08 12:00:00 (GMT)
committerAdrián Medraño Calvo <adrian@medranocalvo.com>2018-10-08 12:00:00 (GMT)
commitdbddfe871076e4a9c10438a8af9c1dfea3b917f6 (patch)
tree8a6b82b70aea8c04445638aeddf2038fe2ad032e
parent9b8c9769c0b7ad4e232550609f8e99d3d5b24f3c (diff)
downloadblt-dbddfe871076e4a9c10438a8af9c1dfea3b917f6.zip
blt-dbddfe871076e4a9c10438a8af9c1dfea3b917f6.tar.gz
blt-dbddfe871076e4a9c10438a8af9c1dfea3b917f6.tar.bz2
Correct display of zero values with -logscale 1
In order to do that, improve the clipping functionality in tkbltGrMisc.C to support infinite coordinates. It also now provides more information with regards to its processing, letting tkbltGrElemLine.C use that same routine instead of duplicade the clipping code.
-rw-r--r--generic/tkbltGrAxis.C4
-rw-r--r--generic/tkbltGrElemLine.C86
-rw-r--r--generic/tkbltGrMisc.C80
-rw-r--r--generic/tkbltGrMisc.h22
4 files changed, 105 insertions, 87 deletions
diff --git a/generic/tkbltGrAxis.C b/generic/tkbltGrAxis.C
index 418abbb..d4a2f00 100644
--- a/generic/tkbltGrAxis.C
+++ b/generic/tkbltGrAxis.C
@@ -1123,7 +1123,7 @@ double Axis::invVMap(double y)
double Axis::hMap(double x)
{
AxisOptions* ops = (AxisOptions*)ops_;
- if ((ops->logScale) && (x != 0.0)) {
+ if (ops->logScale) {
x = log10(fabs(x));
}
/* Map graph coordinate to normalized coordinates [0..1] */
@@ -1137,7 +1137,7 @@ double Axis::hMap(double x)
double Axis::vMap(double y)
{
AxisOptions* ops = (AxisOptions*)ops_;
- if ((ops->logScale) && (y != 0.0)) {
+ if (ops->logScale) {
y = log10(fabs(y));
}
/* Map graph coordinate to normalized coordinates [0..1] */
diff --git a/generic/tkbltGrElemLine.C b/generic/tkbltGrElemLine.C
index 19a572e..513e568 100644
--- a/generic/tkbltGrElemLine.C
+++ b/generic/tkbltGrElemLine.C
@@ -1420,71 +1420,6 @@ void LineElement::mergePens(LineStyle **styleMap)
}
}
-#define CLIP_TOP (1<<0)
-#define CLIP_BOTTOM (1<<1)
-#define CLIP_RIGHT (1<<2)
-#define CLIP_LEFT (1<<3)
-
-int LineElement::outCode(Region2d *extsPtr, Point2d *p)
-{
- int code =0;
- if (p->x > extsPtr->right)
- code |= CLIP_RIGHT;
- else if (p->x < extsPtr->left)
- code |= CLIP_LEFT;
-
- if (p->y > extsPtr->bottom)
- code |= CLIP_BOTTOM;
- else if (p->y < extsPtr->top)
- code |= CLIP_TOP;
-
- return code;
-}
-
-int LineElement::clipSegment(Region2d *extsPtr, int code1, int code2,
- Point2d *p, Point2d *q)
-{
- int inside = ((code1 | code2) == 0);
- int outside = ((code1 & code2) != 0);
-
- /*
- * In the worst case, we'll clip the line segment against each of the four
- * sides of the bounding rectangle.
- */
- while ((!outside) && (!inside)) {
- if (code1 == 0) {
- Point2d *tmp;
- int code;
-
- /* Swap pointers and out codes */
- tmp = p, p = q, q = tmp;
- code = code1, code1 = code2, code2 = code;
- }
- if (code1 & CLIP_LEFT) {
- p->y += (q->y - p->y) *
- (extsPtr->left - p->x) / (q->x - p->x);
- p->x = extsPtr->left;
- } else if (code1 & CLIP_RIGHT) {
- p->y += (q->y - p->y) *
- (extsPtr->right - p->x) / (q->x - p->x);
- p->x = extsPtr->right;
- } else if (code1 & CLIP_BOTTOM) {
- p->x += (q->x - p->x) *
- (extsPtr->bottom - p->y) / (q->y - p->y);
- p->y = extsPtr->bottom;
- } else if (code1 & CLIP_TOP) {
- p->x += (q->x - p->x) *
- (extsPtr->top - p->y) / (q->y - p->y);
- p->y = extsPtr->top;
- }
- code1 = outCode(extsPtr, p);
-
- inside = ((code1 | code2) == 0);
- outside = ((code1 & code2) != 0);
- }
- return (!inside);
-}
-
void LineElement::saveTrace(int start, int length, MapInfo* mapPtr)
{
bltTrace* tracePtr = new bltTrace;
@@ -1537,24 +1472,18 @@ void LineElement::mapTraces(MapInfo *mapPtr)
graphPtr_->extents(&exts);
int count = 1;
- int code1 = outCode(&exts, mapPtr->screenPts);
Point2d* p = mapPtr->screenPts;
Point2d* q = p + 1;
int start;
int ii;
for (ii=1; ii<mapPtr->nScreenPts; ii++, p++, q++) {
- Point2d s;
- s.x = 0;
- s.y = 0;
- int code2 = outCode(&exts, q);
- // Save the coordinates of the last point, before clipping
- if (code2 != 0)
- s = *q;
-
+ // Save the coordinates of the last point before clipping.
+ Point2d originalq = *q;
int broken = BROKEN_TRACE(ops->penDir, p->x, q->x);
- int offscreen = clipSegment(&exts, code1, code2, p, q);
- if (broken || offscreen) {
+ 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),
@@ -1572,14 +1501,13 @@ void LineElement::mapTraces(MapInfo *mapPtr)
// 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 (code2 != 0) {
+ if (clipresult & CLIP_Q) {
start = ii - (count - 1);
saveTrace(start, count, mapPtr);
- mapPtr->screenPts[ii] = s;
+ mapPtr->screenPts[ii] = originalq;
count = 1;
}
}
- code1 = code2;
}
if (count > 1) {
start = ii - count;
diff --git a/generic/tkbltGrMisc.C b/generic/tkbltGrMisc.C
index d951494..aaafcfd 100644
--- a/generic/tkbltGrMisc.C
+++ b/generic/tkbltGrMisc.C
@@ -39,6 +39,7 @@
#include "tkbltGraph.h"
#include "tkbltGrMisc.h"
+#include "tkbltInt.h"
using namespace Blt;
@@ -70,6 +71,63 @@ int Blt::pointInPolygon(Point2d *s, Point2d *points, int nPoints)
return (count & 0x01);
}
+/*
+ *---------------------------------------------------------------------------
+ * Clips a rectangle in one direction where some of the coordinates are
+ * infinite.
+ *---------------------------------------------------------------------------
+ */
+static LineRectClipResult ClipInfinity (double *pa, double *pb, double *qa, double *qb, double region_min, double region_max)
+{
+ int finitepa = isfinite(*pa);
+ int finiteqa = isfinite(*qa);
+
+ if (!finitepa) {
+ if (finiteqa) {
+ if (*pa > 0) { // +Inf
+ *pa = region_max;
+ } else if (*pa < 0) { // -Inf
+ *pa = region_min;
+ } else { // NaN
+ return CLIP_OUTSIDE;
+ }
+ // *qa is finite, simplify to zero slope at *pb.
+ *pb = *qb;
+ return CLIP_P;
+ } else { // Both infinite.
+ int positivepa = *pa > 0;
+ int positiveqa = *qa > 0;
+
+ if (positivepa < positiveqa) { // (p,q) ~ (-Inf,Inf)
+ *pa = region_min;
+ *qa = region_max;
+ } else if (positivepa > positiveqa) { // (p,q) ~ (Inf,-Inf)
+ *pa = region_max;
+ *qa = region_min;
+ } else { // (Inf,Inf), (-Inf,-Inf) or NaN.
+ return CLIP_OUTSIDE;
+ }
+ // At opposite infinities; simplify to zero slope in the middle.
+ *pb = *qb = (*pb + *qb) / 2.0;
+ return CLIP_P | CLIP_Q;
+ }
+ } else if (!finiteqa) {
+ // *pa is finite.
+ if (*qa > 0) { // +Inf
+ *qa = region_max;
+ } else if (*qa < 0) { // -Inf
+ *qa = region_min;
+ } else { // NaN
+ return CLIP_OUTSIDE;
+ }
+ // *pa is finite, simplify to zero slope at *qb.
+ *qb = *pb;
+ return CLIP_Q;
+ }
+ return CLIP_OUTSIDE;
+}
+
+
static int ClipTest (double ds, double dr, double *t1, double *t2)
{
double t;
@@ -77,7 +135,7 @@ static int ClipTest (double ds, double dr, double *t1, double *t2)
if (ds < 0.0) {
t = dr / ds;
if (t > *t2) {
- return 0;
+ return 0; /* Line is outside clipping edge */
}
if (t > *t1) {
*t1 = t;
@@ -85,7 +143,7 @@ static int ClipTest (double ds, double dr, double *t1, double *t2)
} else if (ds > 0.0) {
t = dr / ds;
if (t < *t1) {
- return 0;
+ return 0; /* Line is outside clipping edge */
}
if (t < *t2) {
*t2 = t;
@@ -105,35 +163,47 @@ static int ClipTest (double ds, double dr, double *t1, double *t2)
* of the clipped line segment are returned. The original coordinates
* are overwritten.
*
+ * The return value indicates whether the line was completely outside of
+ * the region, returning CLIP_OUTSIDE; or at least partly inside, returning
+ * CLIP_INSIDE. In the latter case, the result might be or'ed with CLIP_P
+ * if p coordinates were clipped, or CLIP_Q if q coordinates were.
+ *
* Reference:
* Liang, Y-D., and B. Barsky, A new concept and method for
* Line Clipping, ACM, TOG,3(1), 1984, pp.1-22.
*---------------------------------------------------------------------------
*/
-int Blt::lineRectClip(Region2d* regionPtr, Point2d *p, Point2d *q)
+LineRectClipResult Blt::lineRectClip(Region2d* regionPtr, Point2d *p, Point2d *q)
{
double t1, t2;
double dx, dy;
+ LineRectClipResult res = CLIP_OUTSIDE;
+
+ res |= ClipInfinity(&p->x, &p->y, &q->x, &q->y, regionPtr->bottom, regionPtr->top);
t1 = 0.0, t2 = 1.0;
dx = q->x - p->x;
if ((ClipTest (-dx, p->x - regionPtr->left, &t1, &t2)) &&
(ClipTest (dx, regionPtr->right - p->x, &t1, &t2))) {
+ res |= ClipInfinity(&p->y, &p->x, &q->y, &q->x, regionPtr->top, regionPtr->bottom);
+
dy = q->y - p->y;
if ((ClipTest (-dy, p->y - regionPtr->top, &t1, &t2)) &&
(ClipTest (dy, regionPtr->bottom - p->y, &t1, &t2))) {
if (t2 < 1.0) {
q->x = p->x + t2 * dx;
q->y = p->y + t2 * dy;
+ res |= CLIP_Q;
}
if (t1 > 0.0) {
p->x += t1 * dx;
p->y += t1 * dy;
+ res |= CLIP_P;
}
- return 1;
+ return res | CLIP_INSIDE;
}
}
- return 0;
+ return CLIP_OUTSIDE;
}
/*
diff --git a/generic/tkbltGrMisc.h b/generic/tkbltGrMisc.h
index ba86b75..5c16dce 100644
--- a/generic/tkbltGrMisc.h
+++ b/generic/tkbltGrMisc.h
@@ -104,6 +104,26 @@ namespace Blt {
int offset;
} Dashes;
+ typedef enum {
+ CLIP_OUTSIDE = 0,
+ CLIP_INSIDE = 1 << 0,
+ CLIP_P = 1 << 1,
+ CLIP_Q = 1 << 2
+ } LineRectClipResult;
+
+ inline LineRectClipResult operator|(LineRectClipResult a, LineRectClipResult b) {
+ return static_cast<LineRectClipResult>(static_cast<int>(a) | static_cast<int>(b));
+ }
+
+ inline LineRectClipResult operator&(LineRectClipResult a, LineRectClipResult b) {
+ return static_cast<LineRectClipResult>(static_cast<int>(a) & static_cast<int>(b));
+ }
+
+ inline LineRectClipResult & operator|=(LineRectClipResult & rhs, LineRectClipResult v) {
+ rhs = rhs | v;
+ return rhs;
+ }
+
extern char* dupstr(const char*);
extern Graph* getGraphFromWindowData(Tk_Window tkwin);
@@ -111,7 +131,7 @@ namespace Blt {
int nScreenPts);
extern int polyRectClip(Region2d *extsPtr, Point2d *inputPts,
int nInputPts, Point2d *outputPts);
- extern int lineRectClip(Region2d *regionPtr, Point2d *p, Point2d *q);
+ extern LineRectClipResult lineRectClip(Region2d *regionPtr, Point2d *p, Point2d *q);
extern Point2d getProjection (int x, int y, Point2d *p, Point2d *q);
};