The R Project SVN R

Rev

Rev 60710 | Rev 67595 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
1284 ihaka 1
/*
2
 *  R : A Computer Language for Statistical Data Analysis
3
 *  Copyright (C) 1995, 1996  Robert Gentleman and Ross Ihaka
59258 ripley 4
 *  Copyright (C) 1997--2012  The R Core Team
1284 ihaka 5
 *
6
 *  This program is free software; you can redistribute it and/or modify
7
 *  it under the terms of the GNU General Public License as published by
8
 *  the Free Software Foundation; either version 2 of the License, or
9
 *  (at your option) any later version.
10
 *
11
 *  This program is distributed in the hope that it will be useful,
12
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
 *  GNU General Public License for more details.
15
 *
16
 *  You should have received a copy of the GNU General Public License
42307 ripley 17
 *  along with this program; if not, a copy is available at
18
 *  http://www.r-project.org/Licenses/
1284 ihaka 19
 */
20
 
32380 ripley 21
 
5187 hornik 22
#ifdef HAVE_CONFIG_H
7701 hornik 23
#include <config.h>
5187 hornik 24
#endif
25
 
11499 ripley 26
#include <Defn.h>
60667 ripley 27
#include <Internal.h>
51838 ripley 28
#include <float.h>  /* for DBL_MAX */
11499 ripley 29
#include <Rmath.h>
30
#include <Graphics.h>
31
#include <Print.h>
13792 pd 32
#include <R_ext/Boolean.h>
1284 ihaka 33
 
59258 ripley 34
/* filled contours and perspective plots were originally here,
35
   now in graphics/src/plot3d.c .
36
 */
7813 murrell 37
 
59267 ripley 38
#include "contour-common.h"
7813 murrell 39
 
21061 murrell 40
#define CONTOUR_LIST_STEP 100
41
#define CONTOUR_LIST_LEVEL 0
42
#define CONTOUR_LIST_X 1
43
#define CONTOUR_LIST_Y 2
44
 
45
static SEXP growList(SEXP oldlist) {
46
    int i, len;
47
    SEXP templist;
48
    len = LENGTH(oldlist);
49
    templist = PROTECT(allocVector(VECSXP, len + CONTOUR_LIST_STEP));
50
    for (i=0; i<len; i++)
51
	SET_VECTOR_ELT(templist, i, VECTOR_ELT(oldlist, i));
52
    UNPROTECT(1);
53
    return templist;
54
}
55
 
31216 - 56
/*
21061 murrell 57
 * Store the list of segments for a single level in the SEXP
58
 * list that will be returned to the user
59
 */
37012 ripley 60
static
21061 murrell 61
int addContourLines(double *x, int nx, double *y, int ny,
62
		     double *z, double zc, double atom,
63
		     SEGP* segmentDB, int nlines, SEXP container)
64
{
65
    double xend, yend;
55061 ripley 66
    int i, ii, j, jj, ns, dir, nc;
21061 murrell 67
    SEGP seglist, seg, s, start, end;
21594 murrell 68
    SEXP ctr, level, xsxp, ysxp, names;
21061 murrell 69
    /* Begin following contours. */
70
    /* 1. Grab a segment */
71
    /* 2. Follow its tail */
72
    /* 3. Follow its head */
73
    /* 4. Save the contour */
74
    for (i = 0; i < nx - 1; i++)
75
	for (j = 0; j < ny - 1; j++) {
76
	    while ((seglist = segmentDB[i + j * nx])) {
77
		ii = i; jj = j;
78
		start = end = seglist;
79
		segmentDB[i + j * nx] = seglist->next;
80
		xend = seglist->x1;
81
		yend = seglist->y1;
82
		while ((dir = ctr_segdir(xend, yend, x, y,
83
					 &ii, &jj, nx, ny))) {
84
		    segmentDB[ii + jj * nx]
85
			= ctr_segupdate(xend, yend, dir, TRUE,/* = tail */
86
					segmentDB[ii + jj * nx], &seg);
87
		    if (!seg) break;
88
		    end->next = seg;
89
		    end = seg;
90
		    xend = end->x1;
91
		    yend = end->y1;
92
		}
93
		end->next = NULL; /* <<< new for 1.2.3 */
94
		ii = i; jj = j;
95
		xend = seglist->x0;
96
		yend = seglist->y0;
97
		while ((dir = ctr_segdir(xend, yend, x, y,
98
					 &ii, &jj, nx, ny))) {
99
		    segmentDB[ii + jj * nx]
100
			= ctr_segupdate(xend, yend, dir, FALSE,/* ie. head */
101
					segmentDB[ii+jj*nx], &seg);
102
		    if (!seg) break;
103
		    seg->next = start;
104
		    start = seg;
105
		    xend = start->x0;
106
		    yend = start->y0;
107
		}
31216 - 108
 
21061 murrell 109
		/* ns := #{segments of polyline} -- need to allocate */
110
		s = start;
111
		ns = 0;
39176 ripley 112
		/* max_contour_segments: prevent inf.loop (shouldn't be needed) */
113
		while (s && ns < max_contour_segments) {
21061 murrell 114
		    ns++;
115
		    s = s->next;
116
		}
39176 ripley 117
		if(ns == max_contour_segments)
56695 murdoch 118
		    warning(_("contour(): circular/long seglist -- set %s > %d?"), 
119
		            "options(\"max.contour.segments\")", max_contour_segments);
21061 murrell 120
		/*
121
		 * "write" the contour locations into the list of contours
122
		 */
123
		ctr = PROTECT(allocVector(VECSXP, 3));
124
		level = PROTECT(allocVector(REALSXP, 1));
125
		xsxp = PROTECT(allocVector(REALSXP, ns + 1));
126
		ysxp = PROTECT(allocVector(REALSXP, ns + 1));
127
		REAL(level)[0] = zc;
128
		SET_VECTOR_ELT(ctr, CONTOUR_LIST_LEVEL, level);
129
		s = start;
130
		REAL(xsxp)[0] = s->x0;
131
		REAL(ysxp)[0] = s->y0;
132
		ns = 1;
39176 ripley 133
		while (s->next && ns < max_contour_segments) {
21061 murrell 134
		    s = s->next;
135
		    REAL(xsxp)[ns] = s->x0;
136
		    REAL(ysxp)[ns++] = s->y0;
137
		}
138
		REAL(xsxp)[ns] = s->x1;
139
		REAL(ysxp)[ns] = s->y1;
140
		SET_VECTOR_ELT(ctr, CONTOUR_LIST_X, xsxp);
141
		SET_VECTOR_ELT(ctr, CONTOUR_LIST_Y, ysxp);
31216 - 142
		/*
21594 murrell 143
		 * Set the names attribute for the contour
31216 - 144
		 * So that users can extract components using
21594 murrell 145
		 * meaningful names
146
		 */
147
		PROTECT(names = allocVector(STRSXP, 3));
148
		SET_STRING_ELT(names, 0, mkChar("level"));
149
		SET_STRING_ELT(names, 1, mkChar("x"));
150
		SET_STRING_ELT(names, 2, mkChar("y"));
151
		setAttrib(ctr, R_NamesSymbol, names);
31216 - 152
		/*
21061 murrell 153
		 * We're about to add another line to the list ...
154
		 */
155
		nlines += 1;
156
		nc = LENGTH(VECTOR_ELT(container, 0));
157
		if (nlines == nc)
158
		    /* Where does this get UNPROTECTed? */
31216 - 159
		    SET_VECTOR_ELT(container, 0,
21061 murrell 160
				   growList(VECTOR_ELT(container, 0)));
161
		SET_VECTOR_ELT(VECTOR_ELT(container, 0), nlines - 1, ctr);
21594 murrell 162
		UNPROTECT(5);
21061 murrell 163
	    }
164
	}
165
    return nlines;
166
}
167
 
31216 - 168
/*
21061 murrell 169
 * Given nx x values, ny y values, nx*ny z values,
170
 * and nl cut-values in z ...
171
 * ... produce a list of contour lines:
172
 *   list of sub-lists
173
 *     sub-list = x vector, y vector, and cut-value.
174
 */
175
SEXP GEcontourLines(double *x, int nx, double *y, int ny,
34785 murrell 176
		    double *z, double *levels, int nl)
21061 murrell 177
{
50745 ripley 178
    const void *vmax;
21061 murrell 179
    int i, nlines, len;
180
    double atom, zmin, zmax;
181
    SEGP* segmentDB;
182
    SEXP container, mainlist, templist;
31216 - 183
    /*
21061 murrell 184
     * "tie-breaker" values
185
     */
186
    zmin = DBL_MAX;
187
    zmax = DBL_MIN;
188
    for (i = 0; i < nx * ny; i++)
189
	if (R_FINITE(z[i])) {
190
	    if (zmax < z[i]) zmax =  z[i];
191
	    if (zmin > z[i]) zmin =  z[i];
192
	}
193
 
194
    if (zmin >= zmax) {
195
	if (zmin == zmax)
32871 ripley 196
	    warning(_("all z values are equal"));
21061 murrell 197
	else
32871 ripley 198
	    warning(_("all z values are NA"));
21061 murrell 199
	return R_NilValue;
200
    }
201
    /* change to 1e-3, reconsidered because of PR#897
202
     * but 1e-7, and even  2*DBL_EPSILON do not prevent inf.loop in contour().
203
     * maybe something like   16 * DBL_EPSILON * (..).
39176 ripley 204
     * see also max_contour_segments above */
21061 murrell 205
    atom = 1e-3 * (zmax - zmin);
31216 - 206
    /*
21061 murrell 207
     * Create a "container" which is a list with only 1 element.
208
     * The element is the list of lines that will be built up.
209
     * I create the container because this allows me to PROTECT
31216 - 210
     * the container once here and then UNPROTECT it at the end of
211
     * this function and, as long as I always work with
21061 murrell 212
     * VECTOR_ELT(container, 0) and SET_VECTOR_ELT(container, 0)
31216 - 213
     * in functions called from here, I don't need to worry about
21061 murrell 214
     * protectin the list that I am building up.
215
     * Why bother?  Because the list I am building can potentially
216
     * grow and it's awkward to get the PROTECTs/UNPROTECTs right
217
     * when you're in a loop and growing a list.
218
     */
219
    container = PROTECT(allocVector(VECSXP, 1));
31216 - 220
    /*
21061 murrell 221
     * Create "large" list (will trim excess at the end if necesary)
222
     */
223
    SET_VECTOR_ELT(container, 0, allocVector(VECSXP, CONTOUR_LIST_STEP));
224
    nlines = 0;
31216 - 225
    /*
21061 murrell 226
     * Add lines for each contour level
227
     */
228
    for (i = 0; i < nl; i++) {
31216 - 229
	/*
230
	 * The vmaxget/set is to manage the memory that gets
21061 murrell 231
	 * R_alloc'ed in the creation of the segmentDB structure
232
	 */
31216 - 233
	vmax = vmaxget();
234
	/*
21061 murrell 235
	 * Generate a segment database
236
	 */
237
	segmentDB = contourLines(x, nx, y, ny, z, levels[i], atom);
238
	/*
239
	 * Add lines to the list based on the segment database
240
	 */
241
	nlines = addContourLines(x, nx, y, ny, z, levels[i],
242
				 atom, segmentDB, nlines,
243
				 container);
31216 - 244
	vmaxset(vmax);
21061 murrell 245
    }
31216 - 246
    /*
21061 murrell 247
     * Trim the list of lines to the appropriate length.
248
     */
249
    len = LENGTH(VECTOR_ELT(container, 0));
250
    if (nlines < len) {
251
	mainlist = VECTOR_ELT(container, 0);
252
	templist = PROTECT(allocVector(VECSXP, nlines));
253
	for (i=0; i<nlines; i++)
254
	    SET_VECTOR_ELT(templist, i, VECTOR_ELT(mainlist, i));
255
	mainlist = templist;
256
	UNPROTECT(1);  /* UNPROTECT templist */
31216 - 257
    } else
21061 murrell 258
	mainlist = VECTOR_ELT(container, 0);
259
    UNPROTECT(1);  /* UNPROTECT container */
260
    return mainlist;
261
}
262
 
59267 ripley 263
/* This is for contourLines() in package grDevices */
60710 ripley 264
SEXP do_contourLines(SEXP call, SEXP op, SEXP args, SEXP env)
27215 murrell 265
{
55061 ripley 266
    SEXP c, x, y, z;
27215 murrell 267
    int nx, ny, nc;
268
 
60473 ripley 269
    x = PROTECT(coerceVector(CAR(args), REALSXP));
27215 murrell 270
    nx = LENGTH(x);
271
    args = CDR(args);
272
 
60473 ripley 273
    y = PROTECT(coerceVector(CAR(args), REALSXP));
27215 murrell 274
    ny = LENGTH(y);
275
    args = CDR(args);
276
 
60473 ripley 277
    z = PROTECT(coerceVector(CAR(args), REALSXP));
27215 murrell 278
    args = CDR(args);
279
 
280
    /* levels */
60473 ripley 281
    c = PROTECT(coerceVector(CAR(args), REALSXP));
27215 murrell 282
    nc = LENGTH(c);
283
    args = CDR(args);
31216 - 284
 
60473 ripley 285
    SEXP res = GEcontourLines(REAL(x), nx, REAL(y), ny, REAL(z), REAL(c), nc);
286
    UNPROTECT(4);
287
    return res;
27215 murrell 288
}