The R Project SVN R

Rev

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

Rev 20377 Rev 21061
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
/* 
-
 
472
 * Generate a list of segments for a single level
-
 
473
 */
-
 
474
static SEGP* contourLines(double *x, int nx, double *y, int ny,
-
 
475
			 double *z, double zc, double atom)
-
 
476
{
-
 
477
    double f, xl, xh, yl, yh, zll, zhl, zlh, zhh, xx[4], yy[4];
-
 
478
    int i, j, k, l, m, nacode;
-
 
479
    SEGP seglist;
-
 
480
    SEGP *segmentDB;
-
 
481
    /* Initialize the segment data base */
-
 
482
    /* Note we must be careful about resetting */
-
 
483
    /* the top of the stack, otherwise we run out of */
-
 
484
    /* memory after a sequence of displaylist replays */
-
 
485
    /*
-
 
486
     * This reset is done out in GEcontourLines
-
 
487
     */
-
 
488
    segmentDB = (SEGP*)R_alloc(nx*ny, sizeof(SEGP));
-
 
489
    for (i = 0; i < nx; i++)
-
 
490
	for (j = 0; j < ny; j++)
-
 
491
	    segmentDB[i + j * nx] = NULL;
-
 
492
    for (i = 0; i < nx - 1; i++) {
-
 
493
	xl = x[i];
-
 
494
	xh = x[i + 1];
-
 
495
	for (j = 0; j < ny - 1; j++) {
-
 
496
	    yl = y[j];
-
 
497
	    yh = y[j + 1];
-
 
498
	    k = i + j * nx;
-
 
499
	    zll = z[k];
-
 
500
	    zhl = z[k + 1];
-
 
501
	    zlh = z[k + nx];
-
 
502
	    zhh = z[k + nx + 1];
-
 
503
 
-
 
504
	    /* If the value at a corner is exactly equal to a contour level, 
-
 
505
	     * change that value by a tiny amount */
-
 
506
 
-
 
507
	    if (zll == zc) zll += atom;
-
 
508
	    if (zhl == zc) zhl += atom;
-
 
509
	    if (zlh == zc) zlh += atom;
-
 
510
	    if (zhh == zc) zhh += atom;
-
 
511
#ifdef DEBUG_contour
-
 
512
	    /* Haven't seen this happening (MM): */
-
 
513
	    if (zll == zc) REprintf(" [%d,%d] ll: %g\n",i,j, zll);
-
 
514
	    if (zhl == zc) REprintf(" [%d,%d] hl: %g\n",i,j, zhl);
-
 
515
	    if (zlh == zc) REprintf(" [%d,%d] lh: %g\n",i,j, zlh);
-
 
516
	    if (zhh == zc) REprintf(" [%d,%d] hh: %g\n",i,j, zhh);
-
 
517
#endif
-
 
518
	    /* Check for intersections with sides */
-
 
519
 
-
 
520
	    nacode = 0;
-
 
521
	    if (R_FINITE(zll)) nacode += 1;
-
 
522
	    if (R_FINITE(zhl)) nacode += 2;
-
 
523
	    if (R_FINITE(zlh)) nacode += 4;
-
 
524
	    if (R_FINITE(zhh)) nacode += 8;
-
 
525
 
-
 
526
	    k = 0;
-
 
527
	    switch (nacode) {
-
 
528
	    case 15:
-
 
529
		if (ctr_intersect(zll, zhl, zc, &f)) {
-
 
530
		    xx[k] = xl + f * (xh - xl);
-
 
531
		    yy[k] = yl; k++;
-
 
532
		}
-
 
533
		if (ctr_intersect(zll, zlh, zc, &f)) {
-
 
534
		    yy[k] = yl + f * (yh - yl);
-
 
535
		    xx[k] = xl; k++;
-
 
536
		}
-
 
537
		if (ctr_intersect(zhl, zhh, zc, &f)) {
-
 
538
		    yy[k] = yl + f * (yh - yl);
-
 
539
		    xx[k] = xh; k++;
-
 
540
		}
-
 
541
		if (ctr_intersect(zlh, zhh, zc, &f)) {
-
 
542
		    xx[k] = xl + f * (xh - xl);
-
 
543
		    yy[k] = yh; k++;
-
 
544
		}
-
 
545
		break;
-
 
546
	    case 14:
-
 
547
		if (ctr_intersect(zhl, zhh, zc, &f)) {
-
 
548
		    yy[k] = yl + f * (yh - yl);
-
 
549
		    xx[k] = xh; k++;
-
 
550
		}
-
 
551
		if (ctr_intersect(zlh, zhh, zc, &f)) {
-
 
552
		    xx[k] = xl + f * (xh - xl);
-
 
553
		    yy[k] = yh; k++;
-
 
554
		}
-
 
555
		if (ctr_intersect(zlh, zhl, zc, &f)) {
-
 
556
		    xx[k] = xl + f * (xh - xl);
-
 
557
		    yy[k] = yh + f * (yl - yh);
-
 
558
		    k++;
-
 
559
		}
-
 
560
		break;
-
 
561
	    case 13:
-
 
562
		if (ctr_intersect(zll, zlh, zc, &f)) {
-
 
563
		    yy[k] = yl + f * (yh - yl);
-
 
564
		    xx[k] = xl; k++;
-
 
565
		}
-
 
566
		if (ctr_intersect(zlh, zhh, zc, &f)) {
-
 
567
		    xx[k] = xl + f * (xh - xl);
-
 
568
		    yy[k] = yh; k++;
-
 
569
		}
-
 
570
		if (ctr_intersect(zll, zhh, zc, &f)) {
-
 
571
		    xx[k] = xl + f * (xh - xl);
-
 
572
		    yy[k] = yl + f * (yh - yl);
-
 
573
		    k++;
-
 
574
		}
-
 
575
		break;
-
 
576
	    case 11:
-
 
577
		if (ctr_intersect(zhl, zhh, zc, &f)) {
-
 
578
		    yy[k] = yl + f * (yh - yl);
-
 
579
		    xx[k] = xh; k++;
-
 
580
		}
-
 
581
		if (ctr_intersect(zll, zhl, zc, &f)) {
-
 
582
		    xx[k] = xl + f * (xh - xl);
-
 
583
		    yy[k] = yl; k++;
-
 
584
		}
-
 
585
		if (ctr_intersect(zll, zhh, zc, &f)) {
-
 
586
		    xx[k] = xl + f * (xh - xl);
-
 
587
		    yy[k] = yl + f * (yh - yl);
-
 
588
		    k++;
-
 
589
		}
-
 
590
		break;
-
 
591
	    case 7:
-
 
592
		if (ctr_intersect(zll, zlh, zc, &f)) {
-
 
593
		    yy[k] = yl + f * (yh - yl);
-
 
594
		    xx[k] = xl; k++;
-
 
595
		}
-
 
596
		if (ctr_intersect(zll, zhl, zc, &f)) {
-
 
597
		    xx[k] = xl + f * (xh - xl);
-
 
598
		    yy[k] = yl; k++;
-
 
599
		}
-
 
600
		if (ctr_intersect(zlh, zhl, zc, &f)) {
-
 
601
		    xx[k] = xl + f * (xh - xl);
-
 
602
		    yy[k] = yh + f * (yl - yh);
-
 
603
		    k++;
-
 
604
		}
-
 
605
		break;
-
 
606
	    }
-
 
607
 
-
 
608
	    /* We now have k(=2,4) endpoints */
-
 
609
	    /* Decide which to join */
-
 
610
 
-
 
611
	    seglist = NULL;
-
 
612
 
-
 
613
	    if (k > 0) {
-
 
614
		if (k == 2) {
-
 
615
		    seglist = ctr_newseg(xx[0], yy[0], xx[1], yy[1], seglist);
-
 
616
		}
-
 
617
		else if (k == 4) {
-
 
618
		    for (k = 3; k >= 1; k--) {
-
 
619
			m = k;
-
 
620
			xl = xx[k];
-
 
621
			for (l = 0; l < k; l++) {
-
 
622
			    if (xx[l] > xl) {
-
 
623
				xl = xx[l];
-
 
624
				m = l;
-
 
625
			    }
-
 
626
			}
-
 
627
			if (m != k) {
-
 
628
			    xl = xx[k];
-
 
629
			    yl = yy[k];
-
 
630
			    xx[k] = xx[m];
-
 
631
			    yy[k] = yy[m];
-
 
632
			    xx[m] = xl;
-
 
633
			    yy[m] = yl;
-
 
634
			}
-
 
635
		    }
-
 
636
		    seglist = ctr_newseg(xx[0], yy[0], xx[1], yy[1], seglist);
-
 
637
		    seglist = ctr_newseg(xx[2], yy[2], xx[3], yy[3], seglist);
-
 
638
		}
-
 
639
		else error("k != 2 or 4");
-
 
640
	    }
-
 
641
	    segmentDB[i + j * nx] = seglist;
-
 
642
	}
-
 
643
    }
-
 
644
    return segmentDB;
-
 
645
}
-
 
646
 
-
 
647
/* maximal number of line segments of one contour segment: 
-
 
648
 * for preventing infinite loops -- shouldn't be needed --> warning */
-
 
649
#define MAX_ns 25000
-
 
650
 
-
 
651
#define CONTOUR_LIST_STEP 100
-
 
652
#define CONTOUR_LIST_LEVEL 0
-
 
653
#define CONTOUR_LIST_X 1
-
 
654
#define CONTOUR_LIST_Y 2
-
 
655
 
-
 
656
static SEXP growList(SEXP oldlist) {
-
 
657
    int i, len;
-
 
658
    SEXP templist;
-
 
659
    len = LENGTH(oldlist);
-
 
660
    templist = PROTECT(allocVector(VECSXP, len + CONTOUR_LIST_STEP));
-
 
661
    for (i=0; i<len; i++)
-
 
662
	SET_VECTOR_ELT(templist, i, VECTOR_ELT(oldlist, i));
-
 
663
    UNPROTECT(1);
-
 
664
    return templist;
-
 
665
}
-
 
666
 
-
 
667
/* 
-
 
668
 * Store the list of segments for a single level in the SEXP
-
 
669
 * list that will be returned to the user
-
 
670
 */
-
 
671
int addContourLines(double *x, int nx, double *y, int ny,
-
 
672
		     double *z, double zc, double atom,
-
 
673
		     SEGP* segmentDB, int nlines, SEXP container)
-
 
674
{
-
 
675
    double xend, yend;
-
 
676
    int i, ii, j, jj, ns, ns2, dir, nc;
-
 
677
    SEGP seglist, seg, s, start, end;
-
 
678
    SEXP ctr, level, xsxp, ysxp;
-
 
679
    /* Begin following contours. */
-
 
680
    /* 1. Grab a segment */
-
 
681
    /* 2. Follow its tail */
-
 
682
    /* 3. Follow its head */
-
 
683
    /* 4. Save the contour */
-
 
684
    for (i = 0; i < nx - 1; i++)
-
 
685
	for (j = 0; j < ny - 1; j++) {
-
 
686
	    while ((seglist = segmentDB[i + j * nx])) {
-
 
687
		ii = i; jj = j;
-
 
688
		start = end = seglist;
-
 
689
		segmentDB[i + j * nx] = seglist->next;
-
 
690
		xend = seglist->x1;
-
 
691
		yend = seglist->y1;
-
 
692
		while ((dir = ctr_segdir(xend, yend, x, y,
-
 
693
					 &ii, &jj, nx, ny))) {
-
 
694
		    segmentDB[ii + jj * nx]
-
 
695
			= ctr_segupdate(xend, yend, dir, TRUE,/* = tail */
-
 
696
					segmentDB[ii + jj * nx], &seg);
-
 
697
		    if (!seg) break;
-
 
698
		    end->next = seg;
-
 
699
		    end = seg;
-
 
700
		    xend = end->x1;
-
 
701
		    yend = end->y1;
-
 
702
		}
-
 
703
		end->next = NULL; /* <<< new for 1.2.3 */
-
 
704
		ii = i; jj = j;
-
 
705
		xend = seglist->x0;
-
 
706
		yend = seglist->y0;
-
 
707
		while ((dir = ctr_segdir(xend, yend, x, y,
-
 
708
					 &ii, &jj, nx, ny))) {
-
 
709
		    segmentDB[ii + jj * nx]
-
 
710
			= ctr_segupdate(xend, yend, dir, FALSE,/* ie. head */
-
 
711
					segmentDB[ii+jj*nx], &seg);
-
 
712
		    if (!seg) break;
-
 
713
		    seg->next = start;
-
 
714
		    start = seg;
-
 
715
		    xend = start->x0;
-
 
716
		    yend = start->y0;
-
 
717
		}
-
 
718
		
-
 
719
		/* ns := #{segments of polyline} -- need to allocate */
-
 
720
		s = start;
-
 
721
		ns = 0;
-
 
722
		/* MAX_ns: prevent inf.loop (shouldn't be needed) */
-
 
723
		while (s && ns < MAX_ns) {
-
 
724
		    ns++;
-
 
725
		    s = s->next;
-
 
726
		}
-
 
727
		if(ns == MAX_ns)
-
 
728
		    warning("contour(): circular/long seglist -- bug.report()!");
-
 
729
		
-
 
730
		/* countour midpoint : use for labelling sometime (not yet!) */
-
 
731
		if (ns > 3) ns2 = ns/2; else ns2 = -1;
-
 
732
 
-
 
733
		/*
-
 
734
		 * "write" the contour locations into the list of contours
-
 
735
		 */
-
 
736
		ctr = PROTECT(allocVector(VECSXP, 3));
-
 
737
		level = PROTECT(allocVector(REALSXP, 1));
-
 
738
		xsxp = PROTECT(allocVector(REALSXP, ns + 1));
-
 
739
		ysxp = PROTECT(allocVector(REALSXP, ns + 1));
-
 
740
		REAL(level)[0] = zc;
-
 
741
		SET_VECTOR_ELT(ctr, CONTOUR_LIST_LEVEL, level);
-
 
742
		s = start;
-
 
743
		REAL(xsxp)[0] = s->x0;
-
 
744
		REAL(ysxp)[0] = s->y0;
-
 
745
		ns = 1;
-
 
746
		while (s->next && ns < MAX_ns) {
-
 
747
		    s = s->next;
-
 
748
		    REAL(xsxp)[ns] = s->x0;
-
 
749
		    REAL(ysxp)[ns++] = s->y0;
-
 
750
		}
-
 
751
		REAL(xsxp)[ns] = s->x1;
-
 
752
		REAL(ysxp)[ns] = s->y1;
-
 
753
		SET_VECTOR_ELT(ctr, CONTOUR_LIST_X, xsxp);
-
 
754
		SET_VECTOR_ELT(ctr, CONTOUR_LIST_Y, ysxp);
-
 
755
		/* 
-
 
756
		 * We're about to add another line to the list ...
-
 
757
		 */
-
 
758
		nlines += 1;
-
 
759
		nc = LENGTH(VECTOR_ELT(container, 0));
-
 
760
		if (nlines == nc)
-
 
761
		    /* Where does this get UNPROTECTed? */
-
 
762
		    SET_VECTOR_ELT(container, 0, 
-
 
763
				   growList(VECTOR_ELT(container, 0)));
-
 
764
		SET_VECTOR_ELT(VECTOR_ELT(container, 0), nlines - 1, ctr);
-
 
765
		UNPROTECT(4);
-
 
766
	    }
-
 
767
	}
-
 
768
    return nlines;
-
 
769
}
-
 
770
 
-
 
771
/* 
-
 
772
 * Given nx x values, ny y values, nx*ny z values,
-
 
773
 * and nl cut-values in z ...
-
 
774
 * ... produce a list of contour lines:
-
 
775
 *   list of sub-lists
-
 
776
 *     sub-list = x vector, y vector, and cut-value.
-
 
777
 */
-
 
778
SEXP GEcontourLines(double *x, int nx, double *y, int ny,
-
 
779
		    double *z, double *levels, int nl,
-
 
780
		    GEDevDesc *dd)
-
 
781
{
-
 
782
    char *vmax;
-
 
783
    int i, nlines, len;
-
 
784
    double atom, zmin, zmax;
-
 
785
    SEGP* segmentDB;
-
 
786
    SEXP container, mainlist, templist;
-
 
787
    /* 
-
 
788
     * "tie-breaker" values
-
 
789
     */
-
 
790
    zmin = DBL_MAX;
-
 
791
    zmax = DBL_MIN;
-
 
792
    for (i = 0; i < nx * ny; i++)
-
 
793
	if (R_FINITE(z[i])) {
-
 
794
	    if (zmax < z[i]) zmax =  z[i];
-
 
795
	    if (zmin > z[i]) zmin =  z[i];
-
 
796
	}
-
 
797
 
-
 
798
    if (zmin >= zmax) {
-
 
799
	if (zmin == zmax)
-
 
800
	    warning("all z values are equal");
-
 
801
	else
-
 
802
	    warning("all z values are NA");
-
 
803
	return R_NilValue;
-
 
804
    }
-
 
805
    /* change to 1e-3, reconsidered because of PR#897
-
 
806
     * but 1e-7, and even  2*DBL_EPSILON do not prevent inf.loop in contour().
-
 
807
     * maybe something like   16 * DBL_EPSILON * (..).
-
 
808
     * see also MAX_ns above */
-
 
809
    atom = 1e-3 * (zmax - zmin);
-
 
810
    /* 
-
 
811
     * Create a "container" which is a list with only 1 element.
-
 
812
     * The element is the list of lines that will be built up.
-
 
813
     * I create the container because this allows me to PROTECT
-
 
814
     * the container once here and then UNPROTECT it at the end of 
-
 
815
     * this function and, as long as I always work with 
-
 
816
     * VECTOR_ELT(container, 0) and SET_VECTOR_ELT(container, 0)
-
 
817
     * in functions called from here, I don't need to worry about 
-
 
818
     * protectin the list that I am building up.
-
 
819
     * Why bother?  Because the list I am building can potentially
-
 
820
     * grow and it's awkward to get the PROTECTs/UNPROTECTs right
-
 
821
     * when you're in a loop and growing a list.
-
 
822
     */
-
 
823
    container = PROTECT(allocVector(VECSXP, 1));
-
 
824
    /* 
-
 
825
     * Create "large" list (will trim excess at the end if necesary)
-
 
826
     */
-
 
827
    SET_VECTOR_ELT(container, 0, allocVector(VECSXP, CONTOUR_LIST_STEP));
-
 
828
    nlines = 0;
-
 
829
    /* 
-
 
830
     * Add lines for each contour level
-
 
831
     */
-
 
832
    for (i = 0; i < nl; i++) {
-
 
833
	/* 
-
 
834
	 * The vmaxget/set is to manage the memory that gets 
-
 
835
	 * R_alloc'ed in the creation of the segmentDB structure
-
 
836
	 */
-
 
837
	vmax = vmaxget(); 
-
 
838
	/* 
-
 
839
	 * Generate a segment database
-
 
840
	 */
-
 
841
	segmentDB = contourLines(x, nx, y, ny, z, levels[i], atom);
-
 
842
	/*
-
 
843
	 * Add lines to the list based on the segment database
-
 
844
	 */
-
 
845
	nlines = addContourLines(x, nx, y, ny, z, levels[i],
-
 
846
				 atom, segmentDB, nlines,
-
 
847
				 container);
-
 
848
	vmaxset(vmax); 
-
 
849
    }
-
 
850
    /* 
-
 
851
     * Trim the list of lines to the appropriate length.
-
 
852
     */
-
 
853
    len = LENGTH(VECTOR_ELT(container, 0));
-
 
854
    if (nlines < len) {
-
 
855
	mainlist = VECTOR_ELT(container, 0);
-
 
856
	templist = PROTECT(allocVector(VECSXP, nlines));
-
 
857
	for (i=0; i<nlines; i++)
-
 
858
	    SET_VECTOR_ELT(templist, i, VECTOR_ELT(mainlist, i));
-
 
859
	mainlist = templist;
-
 
860
	UNPROTECT(1);  /* UNPROTECT templist */
-
 
861
    } else 
-
 
862
	mainlist = VECTOR_ELT(container, 0);
-
 
863
    UNPROTECT(1);  /* UNPROTECT container */
-
 
864
    return mainlist;
-
 
865
}
-
 
866
 
-
 
867
SEXP GEdrawContourLines();
-
 
868
 
471
static void contour(SEXP x, int nx, SEXP y, int ny, SEXP z, 
869
static void contour(SEXP x, int nx, SEXP y, int ny, SEXP z, 
472
		    double zc,
870
		    double zc,
473
		    SEXP labels, int cnum,
871
		    SEXP labels, int cnum,
474
		    Rboolean drawLabels, int method,
872
		    Rboolean drawLabels, int method,
475
		    Rboolean vectorFonts, int typeface, int fontindex,
873
		    Rboolean vectorFonts, int typeface, int fontindex,
476
		    double atom, DevDesc *dd)
874
		    double atom, DevDesc *dd)
477
{
875
{
478
/* draw a contour for one given contour level `zc' */
876
/* draw a contour for one given contour level `zc' */
479
 
877
 
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
 
-
 
484
    char *vmax;
878
    char *vmax;
485
 
879
 
486
    double f, xl, xh, yl, yh, zll, zhl, zlh, zhh, xx[4], yy[4];
880
    double f, xl, xh, yl, yh, zll, zhl, zlh, zhh, xx[4], yy[4];
487
    double xend, yend;
881
    double xend, yend;
488
    int i, ii, j, jj, k, l, m, nacode, ns, ns2, dir;
882
    int i, ii, j, jj, k, l, m, nacode, ns, ns2, dir;
Line 1073... Line 1467...
1073
    Rboolean vectorFonts = FALSE;
1467
    Rboolean vectorFonts = FALSE;
1074
    int typeface = 0;
1468
    int typeface = 0;
1075
    int fontindex = 0;
1469
    int fontindex = 0;
1076
    double labcex;
1470
    double labcex;
1077
    DevDesc *dd = CurrentDevice();
1471
    DevDesc *dd = CurrentDevice();
-
 
1472
    SEXP result = R_NilValue;
1078
 
1473
 
1079
    GCheckState(dd);
1474
    GCheckState(dd);
1080
 
1475
 
1081
    if (length(args) < 4)
1476
    if (length(args) < 4)
1082
	errorcall(call, "too few arguments");
1477
	errorcall(call, "too few arguments");
Line 1205... Line 1600...
1205
    ltysave = Rf_gpptr(dd)->lty;
1600
    ltysave = Rf_gpptr(dd)->lty;
1206
    colsave = Rf_gpptr(dd)->col;
1601
    colsave = Rf_gpptr(dd)->col;
1207
    lwdsave = Rf_gpptr(dd)->lwd;
1602
    lwdsave = Rf_gpptr(dd)->lwd;
1208
    cexsave = Rf_gpptr(dd)->cex;
1603
    cexsave = Rf_gpptr(dd)->cex;
1209
    labelList = PROTECT(R_NilValue);
1604
    labelList = PROTECT(R_NilValue);
-
 
1605
 
-
 
1606
 
-
 
1607
    /* draw contour for levels[i] */
1210
    GMode(1, dd);
1608
    GMode(1, dd);
1211
    for (i = 0; i < nc; i++) {/* draw contour for levels[i] */
1609
    for (i = 0; i < nc; i++) {
1212
	vmax = vmaxget();
1610
	vmax = vmaxget();
1213
	Rf_gpptr(dd)->lty = INTEGER(lty)[i % nlty];
1611
	Rf_gpptr(dd)->lty = INTEGER(lty)[i % nlty];
1214
	if (Rf_gpptr(dd)->lty == NA_INTEGER)
1612
	if (Rf_gpptr(dd)->lty == NA_INTEGER)
1215
	    Rf_gpptr(dd)->lty = ltysave;
1613
	    Rf_gpptr(dd)->lty = ltysave;
1216
	Rf_gpptr(dd)->col = INTEGER(col)[i % ncol];
1614
	Rf_gpptr(dd)->col = INTEGER(col)[i % ncol];
Line 1223... Line 1621...
1223
	contour(x, nx, y, ny, z, REAL(c)[i], labels, i,
1621
	contour(x, nx, y, ny, z, REAL(c)[i], labels, i,
1224
		drawLabels, method-1,
1622
		drawLabels, method-1,
1225
		vectorFonts, typeface, fontindex, atom, dd);
1623
		vectorFonts, typeface, fontindex, atom, dd);
1226
	vmaxset(vmax);
1624
	vmaxset(vmax);
1227
    }
1625
    }
1228
    GMode(0, dd);
1626
    GMode(0, dd); 
1229
    vmaxset(vmax0);
1627
    vmaxset(vmax0);
1230
    Rf_gpptr(dd)->lty = ltysave;
1628
    Rf_gpptr(dd)->lty = ltysave;
1231
    Rf_gpptr(dd)->col = colsave;
1629
    Rf_gpptr(dd)->col = colsave;
1232
    Rf_gpptr(dd)->lwd = lwdsave;
1630
    Rf_gpptr(dd)->lwd = lwdsave;
1233
    Rf_gpptr(dd)->cex = cexsave;
1631
    Rf_gpptr(dd)->cex = cexsave;
1234
    UNPROTECT(5);
1632
    UNPROTECT(5);
1235
    /* NOTE: only record operation if no "error"  */
1633
    /* NOTE: only record operation if no "error"  */
1236
    /* NOTE: on replay, call == R_NilValue */
1634
    /* NOTE: on replay, call == R_NilValue */
1237
    if (GRecording(call))
1635
    if (GRecording(call))
1238
	recordGraphicOperation(op, oargs, dd);
1636
	recordGraphicOperation(op, oargs, dd);
1239
    return R_NilValue;
1637
    return result;
1240
}
1638
}
1241
 
1639
 
1242
 
1640
 
1243
	/*  F i l l e d   C o n t o u r   P l o t s  */
1641
	/*  F i l l e d   C o n t o u r   P l o t s  */
1244
 
1642