The R Project SVN R

Rev

Rev 12976 | Rev 15321 | Go to most recent revision | Show entire file | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 12976 Rev 13792
Line 25... Line 25...
25
#include <Defn.h>
25
#include <Defn.h>
26
#include <Rmath.h>
26
#include <Rmath.h>
27
#include <Graphics.h>
27
#include <Graphics.h>
28
#include <Rdevices.h>
28
#include <Rdevices.h>
29
#include <Print.h>
29
#include <Print.h>
-
 
30
#include <R_ext/Boolean.h>
30
 
31
 
31
#ifndef HAVE_HYPOT
32
#ifndef HAVE_HYPOT
32
# define hypot pythag
33
# define hypot pythag
33
#endif
34
#endif
34
 
35
 
Line 297... Line 298...
297
    seg->y0 = seg->y1;
298
    seg->y0 = seg->y1;
298
    seg->x1 = x;
299
    seg->x1 = x;
299
    seg->y1 = y;
300
    seg->y1 = y;
300
}
301
}
301
 
302
 
302
	/* Determine the entry direction to the next cell */
303
	/* ctr_segdir(): Determine the entry direction to the next cell */
303
	/* and update the cell indices */
304
	/* and update the cell indices */
304
 
305
 
305
#ifdef OLD
306
#ifdef OLDcontour
306
#define XMATCH(x0,x1) (fabs(x0-x1)<ctr_xtol)
-
 
307
#define YMATCH(y0,y1) (fabs(y0-y1)<ctr_ytol)
-
 
308
#else
-
 
309
#define XMATCH(x0,x1) (fabs(x0-x1)==0)
-
 
310
#define YMATCH(y0,y1) (fabs(y0-y1)==0)
-
 
311
#endif
-
 
312
 
-
 
313
static double ctr_xtol;
307
static double ctr_xtol;
314
static double ctr_ytol;
308
static double ctr_ytol;
-
 
309
#define XMATCH(x0,x1) (fabs(x0-x1) < ctr_xtol)
-
 
310
#define YMATCH(y0,y1) (fabs(y0-y1) < ctr_ytol)
-
 
311
#else
-
 
312
#define XMATCH(x0,x1) (fabs(x0-x1) == 0)
-
 
313
#define YMATCH(y0,y1) (fabs(y0-y1) == 0)
-
 
314
#endif
315
 
315
 
316
static int ctr_segdir(double xend, double yend, double *x, double *y,
316
static int ctr_segdir(double xend, double yend, double *x, double *y,
317
		      int *i, int *j, int nx, int ny)
317
		      int *i, int *j, int nx, int ny)
318
{
318
{
319
    if (YMATCH(yend, y[*j])) {
319
    if (YMATCH(yend, y[*j])) {
Line 345... Line 345...
345
 
345
 
346
/* Search seglist for a segment with endpoint (xend, yend). */
346
/* Search seglist for a segment with endpoint (xend, yend). */
347
/* The cell entry direction is dir, and if tail=1/0 we are */
347
/* The cell entry direction is dir, and if tail=1/0 we are */
348
/* building the tail/head of a contour.	 The matching segment */
348
/* building the tail/head of a contour.	 The matching segment */
349
/* is pointed to by seg and the updated segment list (with */
349
/* is pointed to by seg and the updated segment list (with */
350
/* the matched segment stripped is returned by the funtion. */
350
/* the matched segment stripped) is returned by the funtion. */
351
 
351
 
352
static SEGP ctr_segupdate(double xend, double yend, int dir, int tail,
352
static SEGP ctr_segupdate(double xend, double yend, int dir, Rboolean tail,
353
			  SEGP seglist, SEGP* seg)
353
			  SEGP seglist, SEGP* seg)
354
{
354
{
355
    if (seglist == NULL) {
355
    if (seglist == NULL) {
356
	*seg = NULL;
356
	*seg = NULL;
357
	return NULL;
357
	return NULL;
Line 401... Line 401...
401
   different memory allocation mechanism.
401
   different memory allocation mechanism.
402
*/
402
*/
403
static SEXP labelList;
403
static SEXP labelList;
404
 
404
 
405
static
405
static
406
int distFromEdge(double *xxx, double *yyy, int iii, DevDesc *dd) {
406
double distFromEdge(double *xxx, double *yyy, int iii, DevDesc *dd) {
407
    return fmin2(fmin2(xxx[iii]-dd->gp.usr[0], dd->gp.usr[1]-xxx[iii]),
407
    return fmin2(fmin2(xxx[iii]-dd->gp.usr[0], dd->gp.usr[1]-xxx[iii]),
408
		 fmin2(yyy[iii]-dd->gp.usr[2], dd->gp.usr[3]-yyy[iii]));
408
		 fmin2(yyy[iii]-dd->gp.usr[2], dd->gp.usr[3]-yyy[iii]));
409
}
409
}
410
 
410
 
411
static
411
static
412
int useStart(double *xxx, double *yyy, int ns, DevDesc *dd) {
412
Rboolean useStart(double *xxx, double *yyy, int ns, DevDesc *dd) {
413
    if (distFromEdge(xxx, yyy, 0, dd) < distFromEdge(xxx, yyy, ns-1, dd))
413
    if (distFromEdge(xxx, yyy, 0, dd) < distFromEdge(xxx, yyy, ns-1, dd))
414
	return 1;
414
	return TRUE;
415
    else
415
    else
416
	return 0;
416
	return FALSE;
417
}
417
}
418
 
418
 
419
static
419
static
420
int findGapUp(double *xxx, double *yyy, int ns, double labelDistance,
420
int findGapUp(double *xxx, double *yyy, int ns, double labelDistance,
421
	      DevDesc *dd) {
421
	      DevDesc *dd) {
Line 466... Line 466...
466
	return 0;
466
	return 0;
467
    else
467
    else
468
	return -n;
468
	return -n;
469
}
469
}
470
 
470
 
471
static void contour(SEXP x, int nx, SEXP y, int ny, SEXP z, double zc,
471
static void contour(SEXP x, int nx, SEXP y, int ny, SEXP z, 
-
 
472
		    double zc,
472
		    SEXP labels, int cnum,
473
		    SEXP labels, int cnum,
473
		    Rboolean drawLabels, int method,
474
		    Rboolean drawLabels, int method,
474
		    Rboolean vectorFonts, int typeface, int fontindex,
475
		    Rboolean vectorFonts, int typeface, int fontindex,
475
		    double atom, DevDesc *dd)
476
		    double atom, DevDesc *dd)
476
{
477
{
-
 
478
/* draw a contour for one given contour level `zc' */
-
 
479
 
-
 
480
/* maximal number of line segments of one contour segment: 
-
 
481
 * for preventing infinite loops -- shouldn't be needed --> warning */
-
 
482
#define MAX_ns 25000
-
 
483
 
477
    double f, xl, xh, yl, yh, zll, zhl, zlh, zhh, xx[4], yy[4];
484
    double f, xl, xh, yl, yh, zll, zhl, zlh, zhh, xx[4], yy[4];
478
    double xend, yend;
485
    double xend, yend;
479
    int i, ii, j, jj, k, l, m, nacode, ns, ns2, dir;
486
    int i, ii, j, jj, k, l, m, nacode, ns, ns2, dir;
480
    SEGP seglist, seg, s, start, end;
487
    SEGP seglist, seg, s, start, end;
481
    double *xxx, *yyy;
488
    double *xxx, *yyy;
Line 499... Line 506...
499
    SEXP label2;
506
    SEXP label2;
500
    SEXP lab;
507
    SEXP lab;
501
    Rboolean gotLabel = FALSE;
508
    Rboolean gotLabel = FALSE;
502
    Rboolean ddl;/* Don't draw label -- currently unused, i.e. always FALSE*/
509
    Rboolean ddl;/* Don't draw label -- currently unused, i.e. always FALSE*/
503
 
510
 
-
 
511
#ifdef DEBUG_contour
-
 
512
    Rprintf("contour(lev = %g):\n", zc);
-
 
513
#endif
504
    for (i = 0; i < nx - 1; i++) {
514
    for (i = 0; i < nx - 1; i++) {
505
	xl = REAL(x)[i];
515
	xl = REAL(x)[i];
506
	xh = REAL(x)[i + 1];
516
	xh = REAL(x)[i + 1];
507
	for (j = 0; j < ny - 1; j++) {
517
	for (j = 0; j < ny - 1; j++) {
508
	    yl = REAL(y)[j];
518
	    yl = REAL(y)[j];
Line 510... Line 520...
510
	    k = i + j * nx;
520
	    k = i + j * nx;
511
	    zll = REAL(z)[k];
521
	    zll = REAL(z)[k];
512
	    zhl = REAL(z)[k + 1];
522
	    zhl = REAL(z)[k + 1];
513
	    zlh = REAL(z)[k + nx];
523
	    zlh = REAL(z)[k + nx];
514
	    zhh = REAL(z)[k + nx + 1];
524
	    zhh = REAL(z)[k + nx + 1];
515
	    k = 0;
-
 
516
 
525
 
517
	    /* If the value at a corner is */
526
	    /* If the value at a corner is exactly equal to a contour level, 
518
	    /* exactly equal to a contour */
-
 
519
	    /* level, change the value at */
-
 
520
	    /* corner by a tiny amount. */
527
	     * change that value by a tiny amount */
521
 
-
 
522
	    if (zll == zc) zll = zll + atom;
-
 
523
	    if (zhl == zc) zhl = zhl + atom;
-
 
524
	    if (zlh == zc) zlh = zlh + atom;
-
 
525
	    if (zhh == zc) zhh = zhh + atom;
-
 
526
 
528
 
-
 
529
	    if (zll == zc) zll += atom;
-
 
530
	    if (zhl == zc) zhl += atom;
-
 
531
	    if (zlh == zc) zlh += atom;
-
 
532
	    if (zhh == zc) zhh += atom;
-
 
533
#ifdef DEBUG_contour
-
 
534
	    /* Haven't seen this happening (MM): */
-
 
535
	    if (zll == zc) REprintf(" [%d,%d] ll: %g\n",i,j, zll);
-
 
536
	    if (zhl == zc) REprintf(" [%d,%d] hl: %g\n",i,j, zhl);
-
 
537
	    if (zlh == zc) REprintf(" [%d,%d] lh: %g\n",i,j, zlh);
-
 
538
	    if (zhh == zc) REprintf(" [%d,%d] hh: %g\n",i,j, zhh);
-
 
539
#endif
527
	    /* Check for intersections with sides */
540
	    /* Check for intersections with sides */
528
 
541
 
529
	    nacode = 0;
542
	    nacode = 0;
530
	    if (R_FINITE(zll)) nacode += 1;
543
	    if (R_FINITE(zll)) nacode += 1;
531
	    if (R_FINITE(zhl)) nacode += 2;
544
	    if (R_FINITE(zhl)) nacode += 2;
532
	    if (R_FINITE(zlh)) nacode += 4;
545
	    if (R_FINITE(zlh)) nacode += 4;
533
	    if (R_FINITE(zhh)) nacode += 8;
546
	    if (R_FINITE(zhh)) nacode += 8;
534
 
547
 
-
 
548
	    k = 0;
535
	    switch (nacode) {
549
	    switch (nacode) {
536
	    case 15:
550
	    case 15:
537
		if (ctr_intersect(zll, zhl, zc, &f)) {
551
		if (ctr_intersect(zll, zhl, zc, &f)) {
538
		    xx[k] = xl + f * (xh - xl);
552
		    xx[k] = xl + f * (xh - xl);
539
		    yy[k] = yl; k++;
553
		    yy[k] = yl; k++;
Line 666... Line 680...
666
	    xend = seglist->x1;
680
	    xend = seglist->x1;
667
	    yend = seglist->y1;
681
	    yend = seglist->y1;
668
	    while ((dir = ctr_segdir(xend, yend, REAL(x), REAL(y),
682
	    while ((dir = ctr_segdir(xend, yend, REAL(x), REAL(y),
669
				     &ii, &jj, nx, ny))) {
683
				     &ii, &jj, nx, ny))) {
670
		ctr_SegDB[ii + jj * nx]
684
		ctr_SegDB[ii + jj * nx]
671
		    = ctr_segupdate(xend, yend, dir, 1,
685
		    = ctr_segupdate(xend, yend, dir, TRUE,/* = tail */
672
				    ctr_SegDB[ii + jj * nx], &seg);
686
				    ctr_SegDB[ii + jj * nx], &seg);
673
		if (!seg) break;
687
		if (!seg) break;
674
		end->next = seg;
688
		end->next = seg;
675
		end = seg;
689
		end = seg;
676
		xend = end->x1;
690
		xend = end->x1;
677
		yend = end->y1;
691
		yend = end->y1;
678
	    }
692
	    }
-
 
693
	    end->next = NULL; /* <<< new for 1.2.3 */
679
	    ii = i; jj = j;
694
	    ii = i; jj = j;
680
	    xend = seglist->x0;
695
	    xend = seglist->x0;
681
	    yend = seglist->y0;
696
	    yend = seglist->y0;
682
	    while ((dir = ctr_segdir(xend, yend, REAL(x), REAL(y),
697
	    while ((dir = ctr_segdir(xend, yend, REAL(x), REAL(y),
683
				     &ii, &jj, nx, ny))) {
698
				     &ii, &jj, nx, ny))) {
684
		ctr_SegDB[ii + jj * nx]
699
		ctr_SegDB[ii + jj * nx]
685
		    = ctr_segupdate(xend, yend, dir, 0,
700
		    = ctr_segupdate(xend, yend, dir, FALSE,/* ie. head */
686
				    ctr_SegDB[ii+jj*nx], &seg);
701
				    ctr_SegDB[ii+jj*nx], &seg);
687
		if (!seg) break;
702
		if (!seg) break;
688
		seg->next = start;
703
		seg->next = start;
689
		start = seg;
704
		start = seg;
690
		xend = start->x0;
705
		xend = start->x0;
691
		yend = start->y0;
706
		yend = start->y0;
692
	    }
707
	    }
-
 
708
 
-
 
709
	    /* ns := #{segments of polyline} -- need to allocate */
693
	    s = start;
710
	    s = start;
694
	    ns = 0;
711
	    ns = 0;
-
 
712
	    /* MAX_ns: prevent inf.loop (shouldn't be needed) */
695
	    while (s) {
713
	    while (s && ns < MAX_ns) {
696
		ns++;
714
		ns++;
697
		s = s->next;
715
		s = s->next;
698
	    }
716
	    }
-
 
717
	    if(ns == MAX_ns)
-
 
718
		warning("contour(): circular/long seglist -- bug.report()!");
699
 
719
 
700
	    /* countour midpoint */
-
 
701
	    /* use for labelling sometime */
720
	    /* countour midpoint : use for labelling sometime (not yet!) */
702
 
-
 
703
	    if (ns > 3) ns2 = ns/2;
721
	    if (ns > 3) ns2 = ns/2; else ns2 = -1;
704
	    else ns2 = -1;
-
 
705
 
722
 
706
	    s = start;
-
 
707
	    xxx = (double *) C_alloc(ns + 1, sizeof(double));
723
	    xxx = (double *) C_alloc(ns + 1, sizeof(double));
708
	    yyy = (double *) C_alloc(ns + 1, sizeof(double));
724
	    yyy = (double *) C_alloc(ns + 1, sizeof(double));
-
 
725
	    /* now have the space, go through again: */
-
 
726
	    s = start;
709
	    ns = 0;
727
	    ns = 0;
710
	    xxx[ns] = s->x0;
728
	    xxx[ns] = s->x0;
711
	    yyy[ns++] = s->y0;
729
	    yyy[ns++] = s->y0;
712
	    while (s->next) {
730
	    while (s->next && ns < MAX_ns) {
713
		s = s->next;
731
		s = s->next;
714
		xxx[ns] = s->x0;
732
		xxx[ns] = s->x0;
715
		yyy[ns++] = s->y0;
733
		yyy[ns++] = s->y0;
716
	    }
734
	    }
717
	    xxx[ns] = s->x1;
735
	    xxx[ns] = s->x1;
718
	    yyy[ns++] = s->y1;
736
	    yyy[ns++] = s->y1;
-
 
737
#ifdef DEBUG_contour
-
 
738
	    Rprintf("  [%2d,%2d]: (x,y)[1:%d] = ", i,j, ns);
-
 
739
	    if(ns >= 5)
-
 
740
		Rprintf(" (%g,%g), (%g,%g), ..., (%g,%g)\n", 
-
 
741
			xxx[0],yyy[0], xxx[1],yyy[1], xxx[ns-1],yyy[ns-1]);
-
 
742
	    else
-
 
743
		for(iii = 0; iii < ns; iii++)
-
 
744
		    Rprintf(" (%g,%g)%s", xxx[iii],yyy[iii],
-
 
745
			    (iii < ns-1) ? "," : "\n");
-
 
746
#endif	    
-
 
747
 
719
	    GMode(1, dd);
748
	    GMode(1, dd);
720
 
749
 
-
 
750
	    if (drawLabels) {
721
	    /* If user supplied labels, use i'th one of them
751
		/* If user supplied labels, use i'th one of them
722
	       Otherwise stringify the z-value of the contour */
752
		   Otherwise stringify the z-value of the contour */
723
	    buffer[0] = ' ';
753
		buffer[0] = ' ';
724
	    if (!isNull(labels)) {
754
		if (!isNull(labels)) {
725
		int numl = length(labels);
755
		    int numl = length(labels);
726
		strcpy(&buffer[1], CHAR(STRING_ELT(labels, cnum % numl)));
756
		    strcpy(&buffer[1], CHAR(STRING_ELT(labels, cnum % numl)));
727
	    }
757
		}
728
	    else {
758
		else {
729
		PROTECT(lab = allocVector(REALSXP, 1));
759
		    PROTECT(lab = allocVector(REALSXP, 1));
730
		REAL(lab)[0] = zc;
760
		    REAL(lab)[0] = zc;
731
		lab = labelformat(lab);
761
		    lab = labelformat(lab);
732
		strcpy(&buffer[1], CHAR(STRING_ELT(lab, 0)));
762
		    strcpy(&buffer[1], CHAR(STRING_ELT(lab, 0)));
733
		UNPROTECT(1);
763
		    UNPROTECT(1);
734
	    }
764
		}
735
	    buffer[strlen(buffer)+1] = '\0';
765
		buffer[strlen(buffer)+1] = '\0';
736
	    buffer[strlen(buffer)] = ' ';
766
		buffer[strlen(buffer)] = ' ';
737
 
767
 
738
	    if (vectorFonts) {
768
		if (vectorFonts) {
739
		/* 1, 1 => sans serif, basic font */
769
		    /* 1, 1 => sans serif, basic font */
740
		labelDistance = 
770
		    labelDistance = 
741
		    GVStrWidth((unsigned char *)buffer, typeface, fontindex,
771
			GVStrWidth((unsigned char *)buffer, typeface, fontindex,
742
			       INCHES, dd);
772
				   INCHES, dd);
743
		labelHeight = 
773
		    labelHeight = 
744
		    GVStrHeight((unsigned char *)buffer, typeface, fontindex,
774
			GVStrHeight((unsigned char *)buffer, typeface, fontindex,
745
				INCHES, dd);
775
				    INCHES, dd);
746
	    }
776
		}
747
	    else {
777
		else {
748
		labelDistance = GStrWidth(buffer, INCHES, dd);
778
		    labelDistance = GStrWidth(buffer, INCHES, dd);
749
		labelHeight = GStrHeight(buffer, INCHES, dd);
779
		    labelHeight = GStrHeight(buffer, INCHES, dd);
750
	    }
780
		}
751
 
781
 
752
	    if (drawLabels &&  labelDistance > 0) {
782
		if (labelDistance > 0) {
753
		/* Try to find somewhere to draw the label */
783
		    /* Try to find somewhere to draw the label */
754
		switch (method) {
784
		    switch (method) {
755
		case 0: /* draw label at one end of contour
785
		    case 0: /* draw label at one end of contour
756
			   overwriting contour line
786
			       overwriting contour line
757
			*/
787
			    */
758
		    if (useStart(xxx, yyy, ns, dd) )
788
			if (useStart(xxx, yyy, ns, dd) )
-
 
789
			    indx = 0;
-
 
790
			else
-
 
791
			    indx = ns - 1;
-
 
792
			break;
-
 
793
		    case 1: /* draw label at one end of contour
-
 
794
			       embedded in contour
-
 
795
			       no overlapping labels
-
 
796
			    */
759
			indx = 0;
797
			indx = 0;
760
		    else
-
 
761
			indx = ns - 1;
-
 
762
		    break;
-
 
763
		case 1: /* draw label at one end of contour
-
 
764
			   embedded in contour
-
 
765
			   no overlapping labels
-
 
766
			*/
-
 
767
		    indx = 0;
-
 
768
		    range = 0;
798
			range = 0;
769
		    gotLabel = FALSE;
799
			gotLabel = FALSE;
770
		    if (useStart(xxx, yyy, ns, dd)) {
800
			if (useStart(xxx, yyy, ns, dd)) {
771
			iii = 0;
801
			    iii = 0;
772
			n = findGapUp(xxx, yyy, ns, labelDistance, dd);
802
			    n = findGapUp(xxx, yyy, ns, labelDistance, dd);
773
		    }
803
			}
774
		    else {
804
			else {
775
			n = findGapDown(xxx, yyy, ns, labelDistance, dd);
805
			    n = findGapDown(xxx, yyy, ns, labelDistance, dd);
776
			iii = ns - n - 1;
806
			    iii = ns - n - 1;
777
		    }
-
 
778
		    if (n > 0) {
-
 
779
			/** Find 4 corners of label extents **/
-
 
780
			FindCorners(labelDistance, labelHeight, label1,
-
 
781
				    xxx[iii], yyy[iii],
-
 
782
				    xxx[iii+n], yyy[iii+n], dd);
-
 
783
 
-
 
784
			/** Test corners for intersection with previous labels **/
-
 
785
			label2 = labelList;
-
 
786
			result = 0;
-
 
787
			while ((result == 0) && (label2 != R_NilValue)) {
-
 
788
			    result = TestLabelIntersection(label1, CAR(label2));
-
 
789
			    label2 = CDR(label2);
-
 
790
			}
807
			}
-
 
808
			if (n > 0) {
-
 
809
			    /** Find 4 corners of label extents **/
-
 
810
			    FindCorners(labelDistance, labelHeight, label1,
-
 
811
					xxx[iii], yyy[iii],
-
 
812
					xxx[iii+n], yyy[iii+n], dd);
-
 
813
 
-
 
814
			    /** Test corners for intersection with previous labels **/
-
 
815
			    label2 = labelList;
791
			if (result == 0) {
816
			    result = 0;
-
 
817
			    while ((result == 0) && (label2 != R_NilValue)) {
792
			    result = LabelInsideWindow(label1, dd);
818
				result = TestLabelIntersection(label1, CAR(label2));
-
 
819
				label2 = CDR(label2);
-
 
820
			    }
793
			    if (result == 0) {
821
			    if (result == 0) {
-
 
822
				result = LabelInsideWindow(label1, dd);
-
 
823
				if (result == 0) {
794
				indx = iii;
824
				    indx = iii;
795
				range = n;
825
				    range = n;
796
				gotLabel = TRUE;
826
				    gotLabel = TRUE;
-
 
827
				}
797
			    }
828
			    }
798
			}
829
			}
799
		    }
-
 
800
		    break;
830
			break;
801
		case 2: /* draw label on flattest portion of contour
831
		    case 2: /* draw label on flattest portion of contour
802
			   embedded in contour line
832
			       embedded in contour line
803
			   no overlapping labels
833
			       no overlapping labels
804
			*/
834
			    */
805
		    /* Look for flatest sequence of contour gradients */
835
			/* Look for flatest sequence of contour gradients */
806
		    lowestVariance = 9999999;   /* A large number */
836
			lowestVariance = 9999999;   /* A large number */
807
		    indx = 0;
837
			indx = 0;
808
		    range = 0;
838
			range = 0;
809
		    gotLabel = FALSE;
839
			gotLabel = FALSE;
810
		    for (iii = 0; iii < ns; iii++) {
840
			for (iii = 0; iii < ns; iii++) {
811
			distanceSum = 0;
841
			    distanceSum = 0;
812
			avgGradient = 0;
842
			    avgGradient = 0;
813
			squareSum = 0;
843
			    squareSum = 0;
814
			sum = 0;
844
			    sum = 0;
815
			n = 0;
845
			    n = 0;
816
			zeroCount = 0;
846
			    zeroCount = 0;
817
			jjj = (iii + 1);
847
			    jjj = (iii + 1);
818
			while ((jjj < ns-1) &&
848
			    while ((jjj < ns-1) &&
819
			       (distanceSum < labelDistance)) {
849
				   (distanceSum < labelDistance)) {
820
 
850
 
821
				/* Find a gap big enough for the label
851
				/* Find a gap big enough for the label
822
				   use several segments if necessary
852
				   use several segments if necessary
823
				*/
853
				*/
824
			    dX = xxx[jjj] - xxx[jjj - n - 1];
854
				dX = xxx[jjj] - xxx[jjj - n - 1];
825
			    dY = yyy[jjj] - yyy[jjj - n - 1];
855
				dY = yyy[jjj] - yyy[jjj - n - 1];
826
			    dXC = GConvertXUnits(dX, USER, INCHES, dd);
856
				dXC = GConvertXUnits(dX, USER, INCHES, dd);
827
			    dYC = GConvertYUnits(dY, USER, INCHES, dd);
857
				dYC = GConvertYUnits(dY, USER, INCHES, dd);
828
			    distanceSum = hypot(dXC, dYC);
858
				distanceSum = hypot(dXC, dYC);
829
 
859
 
830
				/* Calculate the variance of the gradients
860
				/* Calculate the variance of the gradients
831
				   of the segments that will make way for the
861
				   of the segments that will make way for the
832
				   label
862
				   label
833
				*/
863
				*/
834
			    deltaX = xxx[jjj] - xxx[jjj - 1];
864
				deltaX = xxx[jjj] - xxx[jjj - 1];
835
			    deltaY = yyy[jjj] - yyy[jjj - 1];
865
				deltaY = yyy[jjj] - yyy[jjj - 1];
836
			    deltaXC = GConvertXUnits(deltaX, USER, INCHES, dd);
866
				deltaXC = GConvertXUnits(deltaX, USER, INCHES, dd);
837
			    deltaYC = GConvertYUnits(deltaY, USER, INCHES, dd);
867
				deltaYC = GConvertYUnits(deltaY, USER, INCHES, dd);
838
			    if (deltaX == 0) {deltaX = 1;}
868
				if (deltaX == 0) {deltaX = 1;}
839
			    avgGradient += (deltaY/deltaX);
869
				avgGradient += (deltaY/deltaX);
840
			    squareSum += avgGradient * avgGradient;
870
				squareSum += avgGradient * avgGradient;
841
			    jjj = (jjj + 1);
871
				jjj = (jjj + 1);
842
			    n += 1;
872
				n += 1;
843
			}
-
 
844
			if (distanceSum < labelDistance)
-
 
845
			    break;
-
 
846
 
-
 
847
			/** Find 4 corners of label extents **/
-
 
848
			FindCorners(labelDistance, labelHeight, label1,
-
 
849
				    xxx[iii], yyy[iii],
-
 
850
				    xxx[iii+n], yyy[iii+n], dd);
-
 
851
 
-
 
852
			/** Test corners for intersection with previous labels **/
-
 
853
			label2 = labelList;
-
 
854
			result = 0;
-
 
855
			while ((result == 0) && (label2 != R_NilValue)) {
-
 
856
			    result = TestLabelIntersection(label1, CAR(label2));
-
 
857
			    label2 = CDR(label2);
-
 
858
			}
-
 
859
			if (result == 0)
-
 
860
			    result = LabelInsideWindow(label1, dd);
-
 
861
			if (result == 0) {
-
 
862
			    variance = (squareSum - (avgGradient * avgGradient) / n) / n;
-
 
863
			    avgGradient /= n;
-
 
864
			    if (variance < lowestVariance) {
-
 
865
				lowestVariance = variance;
-
 
866
				indx = iii;
-
 
867
				range = n;
-
 
868
				avg = avgGradient;
-
 
869
			    }
873
			    }
870
			}
-
 
871
			if (lowestVariance < 9999999)
874
			    if (distanceSum < labelDistance)
872
			    gotLabel = TRUE;
-
 
873
		    }
875
				break;
874
		} /* switch (method) */
-
 
875
 
876
 
876
		if (method == 0) {
-
 
877
		    GPolyline(ns, xxx, yyy, USER, dd);
-
 
878
		    if (vectorFonts)
-
 
879
			GVText(xxx[indx], yyy[indx], USER, buffer,
-
 
880
			       typeface, fontindex,
877
			    /** Find 4 corners of label extents **/
881
			       .5, .5, 0, dd);
-
 
882
		    else
-
 
883
			GText(xxx[indx], yyy[indx], USER, buffer,
-
 
884
			      .5, .5, 0, dd);
-
 
885
		}
-
 
886
		else {
-
 
887
		    for (iii = 0; iii < indx; iii++)
-
 
888
			GLine(xxx[iii], yyy[iii],
-
 
889
			      xxx[iii+1], yyy[iii+1], USER, dd);
-
 
890
		    for (iii = indx+range; iii < ns - 1; iii++)
878
			    FindCorners(labelDistance, labelHeight, label1,
891
			GLine(xxx[iii], yyy[iii],
879
					xxx[iii], yyy[iii],
892
			      xxx[iii+1], yyy[iii+1], USER, dd);
880
					xxx[iii+n], yyy[iii+n], dd);
893
 
881
 
894
		    if (gotLabel) {
-
 
895
			/* find which plot edge we are closest to */
882
			    /** Test corners for intersection with previous labels **/
896
			int closest; /* 0 = indx,  1 = indx+range */
-
 
897
			double dx1, dx2, dy1, dy2, dmin;
-
 
898
			dx1 = fmin2((xxx[indx] - dd->gp.usr[0]),
-
 
899
				    (dd->gp.usr[1] - xxx[indx]));
-
 
900
			dx2 = fmin2((dd->gp.usr[1] - xxx[indx+range]),
-
 
901
				    (xxx[indx+range] - dd->gp.usr[0]));
-
 
902
			if (dx1 < dx2) {
-
 
903
			    closest = 0;
883
			    label2 = labelList;
904
			    dmin = dx1;
-
 
905
			} else {
-
 
906
			    closest = 1;
884
			    result = 0;
907
			    dmin = dx2;
-
 
908
			}
-
 
909
			dy1 = fmin2((yyy[indx] - dd->gp.usr[2]),
885
			    while ((result == 0) && (label2 != R_NilValue)) {
910
				    (dd->gp.usr[3] - yyy[indx]));
886
				result = TestLabelIntersection(label1, CAR(label2));
911
			if (closest && (dy1 < dmin)) {
-
 
912
			    closest = 0;
-
 
913
			    dmin = dy1;
-
 
914
			} else if (dy1 < dmin)
887
				label2 = CDR(label2);
915
			    dmin = dy1;
888
			    }
916
			dy2 = fmin2((dd->gp.usr[3] - yyy[indx+range]),
-
 
917
				    (yyy[indx+range] - dd->gp.usr[2]));
-
 
918
			if (!closest && (dy2 < dmin))
-
 
919
			    closest = 1;
889
			    if (result == 0)
920
 
-
 
921
			dx = GConvertXUnits(xxx[indx+range] - xxx[indx],
-
 
922
					    USER, INCHES, dd);
-
 
923
			dy = GConvertYUnits(yyy[indx+range] - yyy[indx],
-
 
924
					    USER, INCHES, dd);
-
 
925
			dxy = hypot(dx, dy);
-
 
926
 
-
 
927
			/* save the current label for checking overlap */
-
 
928
			label2 = allocVector(REALSXP, 8);
890
				result = LabelInsideWindow(label1, dd);
929
 
-
 
930
			FindCorners(labelDistance, labelHeight, label2,
-
 
931
				    xxx[indx], yyy[indx],
891
			    if (result == 0) {
932
				    xxx[indx+range], yyy[indx+range], dd);
-
 
933
			UNPROTECT_PTR(labelList);
-
 
934
			labelList = PROTECT(CONS(label2, labelList));
892
				variance = (squareSum - (avgGradient * avgGradient) / n) / n;
935
 
-
 
936
			ddl = FALSE;
-
 
937
			/* draw an extra bit of segment if the label
-
 
938
			   doesn't fill the gap */
-
 
939
			if (closest) {
893
				avgGradient /= n;
940
			    xStart = xxx[indx+range] -
894
				if (variance < lowestVariance) {
941
				(xxx[indx+range] - xxx[indx]) *
895
				    lowestVariance = variance;
942
				labelDistance / dxy;
896
				    indx = iii;
943
			    yStart = yyy[indx+range] -
-
 
944
				(yyy[indx+range] - yyy[indx]) *
-
 
945
				labelDistance / dxy;
897
				    range = n;
946
			    if (labelDistance / dxy < 1)
-
 
947
				GLine(xxx[indx], yyy[indx],
-
 
948
				      xStart, yStart,
898
				    avg = avgGradient;
949
				      USER, dd);
899
				}
950
			} else {
900
			    }
951
			    xStart = xxx[indx] +
-
 
952
				(xxx[indx+range] - xxx[indx]) *
-
 
953
				labelDistance / dxy;
-
 
954
			    yStart = yyy[indx] +
-
 
955
				(yyy[indx+range] - yyy[indx]) *
-
 
956
				labelDistance / dxy;
-
 
957
			    if (labelDistance / dxy < 1)
901
			    if (lowestVariance < 9999999)
958
				GLine(xStart, yStart,
-
 
959
				      xxx[indx+range], yyy[indx+range],
-
 
960
				      USER, dd);
902
				gotLabel = TRUE;
961
			}
903
			}
-
 
904
		    } /* switch (method) */
962
 
905
 
963
			/*** Draw contour labels ***/
906
		    if (method == 0) {
-
 
907
			GPolyline(ns, xxx, yyy, USER, dd);
-
 
908
			if (vectorFonts)
964
			if (xxx[indx] < xxx[indx+range]) {
909
			    GVText(xxx[indx], yyy[indx], USER, buffer,
-
 
910
				   typeface, fontindex,
965
			    if (closest) {
911
				   .5, .5, 0, dd);
-
 
912
			else
-
 
913
			    GText(xxx[indx], yyy[indx], USER, buffer,
966
				ux = xStart;
914
				  .5, .5, 0, dd);
-
 
915
		    }
-
 
916
		    else {
-
 
917
			for (iii = 0; iii < indx; iii++)
-
 
918
			    GLine(xxx[iii], yyy[iii],
-
 
919
				  xxx[iii+1], yyy[iii+1], USER, dd);
-
 
920
			for (iii = indx+range; iii < ns - 1; iii++)
-
 
921
			    GLine(xxx[iii], yyy[iii],
-
 
922
				  xxx[iii+1], yyy[iii+1], USER, dd);
-
 
923
 
967
				uy = yStart;
924
			if (gotLabel) {
-
 
925
			    /* find which plot edge we are closest to */
-
 
926
			    int closest; /* 0 = indx,  1 = indx+range */
-
 
927
			    double dx1, dx2, dy1, dy2, dmin;
-
 
928
			    dx1 = fmin2((xxx[indx] - dd->gp.usr[0]),
-
 
929
					(dd->gp.usr[1] - xxx[indx]));
-
 
930
			    dx2 = fmin2((dd->gp.usr[1] - xxx[indx+range]),
968
				vx = xxx[indx+range];
931
					(xxx[indx+range] - dd->gp.usr[0]));
969
				vy = yyy[indx+range];
932
			    if (dx1 < dx2) {
-
 
933
				closest = 0;
-
 
934
				dmin = dx1;
970
			    } else {
935
			    } else {
971
				ux = xxx[indx];
-
 
972
				uy = yyy[indx];
-
 
973
				vx = xStart;
936
				closest = 1;
974
				vy = yStart;
937
				dmin = dx2;
975
			    }
938
			    }
-
 
939
			    dy1 = fmin2((yyy[indx] - dd->gp.usr[2]),
-
 
940
					(dd->gp.usr[3] - yyy[indx]));
-
 
941
			    if (closest && (dy1 < dmin)) {
-
 
942
				closest = 0;
-
 
943
				dmin = dy1;
-
 
944
			    } else if (dy1 < dmin)
976
			}
945
				dmin = dy1;
-
 
946
			    dy2 = fmin2((dd->gp.usr[3] - yyy[indx+range]),
-
 
947
					(yyy[indx+range] - dd->gp.usr[2]));
-
 
948
			    if (!closest && (dy2 < dmin))
977
			else {
949
				closest = 1;
-
 
950
 
-
 
951
			    dx = GConvertXUnits(xxx[indx+range] - xxx[indx],
-
 
952
						USER, INCHES, dd);
-
 
953
			    dy = GConvertYUnits(yyy[indx+range] - yyy[indx],
-
 
954
						USER, INCHES, dd);
-
 
955
			    dxy = hypot(dx, dy);
-
 
956
 
-
 
957
			    /* save the current label for checking overlap */
-
 
958
			    label2 = allocVector(REALSXP, 8);
-
 
959
 
-
 
960
			    FindCorners(labelDistance, labelHeight, label2,
-
 
961
					xxx[indx], yyy[indx],
-
 
962
					xxx[indx+range], yyy[indx+range], dd);
-
 
963
			    UNPROTECT_PTR(labelList);
-
 
964
			    labelList = PROTECT(CONS(label2, labelList));
-
 
965
 
-
 
966
			    ddl = FALSE;
-
 
967
			    /* draw an extra bit of segment if the label
-
 
968
			       doesn't fill the gap */
978
			    if (closest) {
969
			    if (closest) {
979
				ux = xxx[indx+range];
970
				xStart = xxx[indx+range] -
-
 
971
				    (xxx[indx+range] - xxx[indx]) *
-
 
972
				    labelDistance / dxy;
980
				uy = yyy[indx+range];
973
				yStart = yyy[indx+range] -
-
 
974
				    (yyy[indx+range] - yyy[indx]) *
-
 
975
				    labelDistance / dxy;
-
 
976
				if (labelDistance / dxy < 1)
-
 
977
				    GLine(xxx[indx], yyy[indx],
981
				vx = xStart;
978
					  xStart, yStart,
982
				vy = yStart;
979
					  USER, dd);
983
			    } else {
980
			    } else {
984
				ux = xStart;
981
				xStart = xxx[indx] +
-
 
982
				    (xxx[indx+range] - xxx[indx]) *
985
				uy = yStart;
983
				    labelDistance / dxy;
986
				vx = xxx[indx];
984
				yStart = yyy[indx] +
-
 
985
				    (yyy[indx+range] - yyy[indx]) *
-
 
986
				    labelDistance / dxy;
-
 
987
				if (labelDistance / dxy < 1)
-
 
988
				    GLine(xStart, yStart,
-
 
989
					  xxx[indx+range], yyy[indx+range],
987
				vy = yyy[indx];
990
					  USER, dd);
988
			    }
991
			    }
989
			}
-
 
990
 
992
 
-
 
993
			    /*** Draw contour labels ***/
-
 
994
			    if (xxx[indx] < xxx[indx+range]) {
-
 
995
				if (closest) {
-
 
996
				    ux = xStart;
-
 
997
				    uy = yStart;
-
 
998
				    vx = xxx[indx+range];
-
 
999
				    vy = yyy[indx+range];
-
 
1000
				} else {
-
 
1001
				    ux = xxx[indx];
-
 
1002
				    uy = yyy[indx];
-
 
1003
				    vx = xStart;
-
 
1004
				    vy = yStart;
-
 
1005
				}
-
 
1006
			    }
-
 
1007
			    else {
-
 
1008
				if (closest) {
-
 
1009
				    ux = xxx[indx+range];
-
 
1010
				    uy = yyy[indx+range];
-
 
1011
				    vx = xStart;
-
 
1012
				    vy = yStart;
-
 
1013
				} else {
-
 
1014
				    ux = xStart;
-
 
1015
				    uy = yStart;
-
 
1016
				    vx = xxx[indx];
-
 
1017
				    vy = yyy[indx];
-
 
1018
				}
-
 
1019
			    }
-
 
1020
 
991
			if (!ddl) {
1021
			    if (!ddl) {
992
				/* convert to INCHES for calculation of
1022
				/* convert to INCHES for calculation of
993
				   angle to draw text
1023
				   angle to draw text
994
				*/
1024
				*/
995
			    GConvert(&ux, &uy, USER, INCHES, dd);
1025
				GConvert(&ux, &uy, USER, INCHES, dd);
996
			    GConvert(&vx, &vy, USER, INCHES, dd);
1026
				GConvert(&vx, &vy, USER, INCHES, dd);
997
				/* 1, 1 => sans serif, basic font
1027
				/* 1, 1 => sans serif, basic font
998
				   0, .5 => left, centre justified */
1028
				   0, .5 => left, centre justified */
999
			    if (vectorFonts)
1029
				if (vectorFonts)
1000
				GVText(ux, uy, INCHES, buffer,
1030
				    GVText(ux, uy, INCHES, buffer,
1001
				       typeface, fontindex, 0, .5,
1031
					   typeface, fontindex, 0, .5,
1002
				       (180 / 3.14) * atan2(vy - uy, vx - ux),
1032
					   (180 / 3.14) * atan2(vy - uy, vx - ux),
1003
				       dd);
1033
					   dd);
1004
			    else
1034
				else
1005
				GText (ux, uy, INCHES, buffer, 0, .5,
1035
				    GText (ux, uy, INCHES, buffer, 0, .5,
1006
				       (180 / 3.14) * atan2(vy - uy, vx - ux),
1036
					   (180 / 3.14) * atan2(vy - uy, vx - ux),
1007
				       dd);
1037
					   dd);
1008
			}
1038
			    }
1009
		    } /* if (gotLabel) */
1039
			} /* if (gotLabel) */
1010
		} /* if (method == 0) else ... */
1040
		    } /* if (method == 0) else ... */
1011
	    } /* if (drawLabels && labelDistance > 0) */
1041
		} /* if (labelDistance > 0) */
-
 
1042
 
-
 
1043
	    } /* if (drawLabels) */
1012
	    else {
1044
	    else {
1013
		GPolyline(ns, xxx, yyy, USER, dd);
1045
		GPolyline(ns, xxx, yyy, USER, dd);
1014
	    }
1046
	    }
1015
 
1047
 
1016
	    GMode(0, dd);
1048
	    GMode(0, dd);
Line 1019... Line 1051...
1019
	} /* while */
1051
	} /* while */
1020
      } /* for(i .. )  for(j ..) */
1052
      } /* for(i .. )  for(j ..) */
1021
    UNPROTECT_PTR(label1); /* pwwwargh! This is messy, but last thing
1053
    UNPROTECT_PTR(label1); /* pwwwargh! This is messy, but last thing
1022
			      protected is likely labelList, and that needs
1054
			      protected is likely labelList, and that needs
1023
			      to be preserved across calls */
1055
			      to be preserved across calls */
1024
 }
1056
}
1025
 
-
 
1026
/* contour(x,y,z, levels, col, lty) */
-
 
1027
 
1057
 
-
 
1058
/* contour(x, y, z, levels, labels, labcex, drawlabels, 
-
 
1059
 *         method, vfont, col = col, lty = lty, lwd = lwd)
-
 
1060
 */
1028
SEXP do_contour(SEXP call, SEXP op, SEXP args, SEXP env)
1061
SEXP do_contour(SEXP call, SEXP op, SEXP args, SEXP env)
1029
{
1062
{
1030
    SEXP oargs, c, x, y, z, vfont, col, lty, lwd, labels;
1063
    SEXP oargs, c, x, y, z, vfont, col, lty, lwd, labels;
1031
    int i, j, nx, ny, nc, ncol, nlty, nlwd;
1064
    int i, j, nx, ny, nc, ncol, nlty, nlwd;
1032
    int ltysave, colsave, lwdsave;
1065
    int ltysave, colsave, lwdsave;
Line 1060... Line 1093...
1060
 
1093
 
1061
    z = CAR(args);
1094
    z = CAR(args);
1062
    internalTypeCheck(call, z, REALSXP);
1095
    internalTypeCheck(call, z, REALSXP);
1063
    args = CDR(args);
1096
    args = CDR(args);
1064
 
1097
 
-
 
1098
    /* levels */
1065
    c = CAR(args);
1099
    c = CAR(args);
1066
    internalTypeCheck(call, c, REALSXP);
1100
    internalTypeCheck(call, c, REALSXP);
1067
    nc = LENGTH(c);
1101
    nc = LENGTH(c);
1068
    args = CDR(args);
1102
    args = CDR(args);
1069
 
1103
 
Line 1123... Line 1157...
1123
	    errorcall(call, "missing y values");
1157
	    errorcall(call, "missing y values");
1124
	if (i > 0 && REAL(y)[i] < REAL(y)[i - 1])
1158
	if (i > 0 && REAL(y)[i] < REAL(y)[i - 1])
1125
	    errorcall(call, "increasing y values expected");
1159
	    errorcall(call, "increasing y values expected");
1126
    }
1160
    }
1127
 
1161
 
-
 
1162
#ifdef OLDcontour
1128
    ctr_xtol = 1e-3 * fabs(REAL(x)[nx-1]-REAL(x)[0]);
1163
    ctr_xtol = 1e-3 * fabs(REAL(x)[nx-1]-REAL(x)[0]);
1129
    ctr_ytol = 1e-3 * fabs(REAL(y)[ny-1]-REAL(y)[0]);
1164
    ctr_ytol = 1e-3 * fabs(REAL(y)[ny-1]-REAL(y)[0]);
-
 
1165
#endif
1130
 
1166
 
1131
    for (i = 0; i < nc; i++)
1167
    for (i = 0; i < nc; i++)
1132
	if (!R_FINITE(REAL(c)[i]))
1168
	if (!R_FINITE(REAL(c)[i]))
1133
	    errorcall(call, "illegal NA contour values");
1169
	    errorcall(call, "illegal NA contour values");
1134
 
1170
 
Line 1146... Line 1182...
1146
	else
1182
	else
1147
	    warning("all z values are NA");
1183
	    warning("all z values are NA");
1148
	return R_NilValue;
1184
	return R_NilValue;
1149
    }
1185
    }
1150
 
1186
 
-
 
1187
#ifdef OLDcontour 
-
 
1188
    /* R versions up to incl. 0.61.3, 1998-05-03): */
1151
    /* PREVIOUSLY: atom = DBL_EPSILON * (zmax - zmin); */
1189
    atom = DBL_EPSILON * (zmax - zmin);
1152
 
1190
#else
-
 
1191
    /* change to 1e-3, reconsidered because of PR#897
-
 
1192
     * but 1e-7, and even  2*DBL_EPSILON do not prevent inf.loop in contour().
-
 
1193
     * maybe something like   16 * DBL_EPSILON * (..).
-
 
1194
     * see also MAX_ns above */
1153
    atom = 1e-3 * (zmax - zmin);
1195
    atom = 1e-3 * (zmax - zmin);
-
 
1196
#endif
1154
 
1197
 
1155
    /* Initialize the segment data base */
1198
    /* Initialize the segment data base */
-
 
1199
 
1156
    /* Note we must be careful about resetting */
1200
    /* Note we must be careful about resetting */
1157
    /* the top of the stack, otherwise we run out of */
1201
    /* the top of the stack, otherwise we run out of */
1158
    /* memory after a sequence of displaylist replays */
1202
    /* memory after a sequence of displaylist replays */
1159
 
1203
 
1160
    vmax0 = vmaxget();
1204
    vmax0 = vmaxget();
Line 1170... Line 1214...
1170
    colsave = dd->gp.col;
1214
    colsave = dd->gp.col;
1171
    lwdsave = dd->gp.lwd;
1215
    lwdsave = dd->gp.lwd;
1172
    cexsave = dd->gp.cex;
1216
    cexsave = dd->gp.cex;
1173
    labelList = PROTECT(R_NilValue);
1217
    labelList = PROTECT(R_NilValue);
1174
    GMode(1, dd);
1218
    GMode(1, dd);
1175
    for (i = 0; i < nc; i++) {
1219
    for (i = 0; i < nc; i++) {/* draw contour for levels[i] */
1176
	vmax = vmaxget();
1220
	vmax = vmaxget();
1177
	dd->gp.lty = INTEGER(lty)[i % nlty];
1221
	dd->gp.lty = INTEGER(lty)[i % nlty];
1178
	if (dd->gp.lty == NA_INTEGER)
1222
	if (dd->gp.lty == NA_INTEGER)
1179
	    dd->gp.lty = ltysave;
1223
	    dd->gp.lty = ltysave;
1180
	dd->gp.col = INTEGER(col)[i % ncol];
1224
	dd->gp.col = INTEGER(col)[i % ncol];
Line 1201... Line 1245...
1201
    if (GRecording(call))
1245
    if (GRecording(call))
1202
	recordGraphicOperation(op, oargs, dd);
1246
	recordGraphicOperation(op, oargs, dd);
1203
    return R_NilValue;
1247
    return R_NilValue;
1204
}
1248
}
1205
 
1249
 
-
 
1250
 
1206
	/*  F i l l e d   C o n t o u r   P l o t s  */
1251
	/*  F i l l e d   C o n t o u r   P l o t s  */
1207
 
1252
 
1208
	/*  R o s s  I h a k a,  M a r c h  1 9 9 9  */
1253
	/*  R o s s  I h a k a,  M a r c h  1 9 9 9  */
1209
 
1254
 
1210
static void
1255
static void
Line 1318... Line 1363...
1318
}
1363
}
1319
 
1364
 
1320
/* FIXME: [Code consistency] Use macro for the parallel parts of
1365
/* FIXME: [Code consistency] Use macro for the parallel parts of
1321
	  do_contour, do_filledcontour & do_image ...
1366
	  do_contour, do_filledcontour & do_image ...
1322
*/
1367
*/
-
 
1368
 
-
 
1369
/* filledcontour(x, y, z, levels, col) */
1323
SEXP do_filledcontour(SEXP call, SEXP op, SEXP args, SEXP env)
1370
SEXP do_filledcontour(SEXP call, SEXP op, SEXP args, SEXP env)
1324
{
1371
{
1325
    SEXP oargs, sx, sy, sz, sc, scol;
1372
    SEXP oargs, sx, sy, sz, sc, scol;
1326
    double *x, *y, *z, *c;
1373
    double *x, *y, *z, *c;
1327
    unsigned *col;
1374
    unsigned *col;
Line 1347... Line 1394...
1347
    sz = CAR(args);
1394
    sz = CAR(args);
1348
    internalTypeCheck(call, sz, REALSXP);
1395
    internalTypeCheck(call, sz, REALSXP);
1349
    nz = length(sz);
1396
    nz = length(sz);
1350
    args = CDR(args);
1397
    args = CDR(args);
1351
 
1398
 
1352
    sc = CAR(args);
1399
    sc = CAR(args);/* levels */
1353
    internalTypeCheck(call, sc, REALSXP);
1400
    internalTypeCheck(call, sc, REALSXP);
1354
    nc = length(sc);
1401
    nc = length(sc);
1355
    args = CDR(args);
1402
    args = CDR(args);
1356
 
1403
 
1357
    PROTECT(scol = FixupCol(CAR(args), NA_INTEGER));
1404
    PROTECT(scol = FixupCol(CAR(args), NA_INTEGER));
Line 1417... Line 1464...
1417
    return R_NilValue;
1464
    return R_NilValue;
1418
 
1465
 
1419
 badxy:
1466
 badxy:
1420
    errorcall(call, "invalid x / y values or limits");
1467
    errorcall(call, "invalid x / y values or limits");
1421
 badlev:
1468
 badlev:
1422
    errorcall(call, "invalid contour levels");
1469
    errorcall(call, "invalid contour levels: must be strictly increasing");
1423
    return R_NilValue;  /* never used; to keep -Wall happy */
1470
    return R_NilValue;  /* never used; to keep -Wall happy */
1424
}
1471
}
1425
 
1472
 
1426
 
1473
 
1427
	/*  I m a g e   R e n d e r i n g  */
1474
	/*  I m a g e   R e n d e r i n g  */