Clip/Cut everything outside of Polygon or fill the outside with white

2.3k views Asked by At

I have a square of colored noise with an triangle on it. Now, I want the polygon to cut this noise like a "cookie cutter" on christmas. Resulting in an triangle of noise that is surrounded by a polygon path.

How can i clip all pixels that overlap the Polygon border and then save it as pdf?

I came up with 2 ideas:

  • Method 1 use a function that tests whether the pixel (colored noise) falls in the shape or not. Lets do it!
    Problem: The edges of the border pixels go out of the line. In this example its quite minimal. You could argue just making the polygon-line a little bit bigger.
  • Method 2 Inverse the Polygon Shape (equal to: fill outside of polygon) and then fill it with white.
    Problem: In the plot preview window the result looks like i want it. When i save it as PDF i get an result of everything is white with the black polygon shapes.

Reproducible example:

library(magrittr)
library(ggplot2)
library(SDMTools)
polyGony <- c(0,0,100,50,50,100) %>% matrix(ncol=2,byrow = T) %>% as.data.frame()
deltaN <- 200  #grid width
sp1<-seq(1,100,length=deltaN)
sp2<-seq(1,100,length=deltaN)
sp<-expand.grid(x=sp1,y=sp2)

set.seed(1337)
sp$z <- sample(1:30,nrow(sp),replace = T)

# Method 1
outin = SDMTools::pnt.in.poly(sp[,1:2],polyGony)
outin$z <- sp$z
pointsInsideTri <- outin[outin$pip==1,-3]

p <- ggplot(pointsInsideTri, aes(x, y)) +
  geom_raster(aes(fill = z)) +
  scale_fill_gradientn(colours=c("#FFCd94", "#FF69B4", "#FF0000","#4C0000","#000000"))

p + geom_polygon(data = polyGony, aes(V1,V2),color="black", fill=NA) + theme(aspect.ratio = 1)

# Method 2
outSQ <-c(0,0,100,0,100,100,0,100)
invPolyGony <- c(outSQ,0,0,100,50,50,100) %>% matrix(ncol=2,byrow = T) %>% as.data.frame()


    p <- ggplot(sp, aes(x, y)) +
      geom_raster(aes(fill = z)) +
      scale_fill_gradientn(colours=c("#FFCd94", "#FF69B4", "#FF0000","#4C0000","#000000"))

    p + geom_polygon(data = invPolyGony, aes(V1,V2) ,colour="black", fill="white") + theme(aspect.ratio = 1)
1

There are 1 answers

2
Andre Elrico On BEST ANSWER

i now know what the problem was. In order to fill everything outside of a polygon, the path (the hole in the middle) needs to "run" clockwise, the outter border needs to run counter-clockwise.

I made a simple example. We have a polygon of a star. I want everything outside of the star to be red.

star <- c(25.000,1.000,31.000,18.000,49.000,18.000,35.000,29.000,40.000,46.000,
          25.000,36.000,10.000,46.000,15.000,29.000,1.000,18.000,19.000,18.000) %>% matrix(ncol=2, byrow=T)
star <- rbind(star,star[1,])
rim  <- c(0,0, 50,0, 50,50,0,50,0,0) %>% matrix(ncol=2, byrow=T)

datapolyM <- rbind(rim,star) %>% as.data.frame()
names(datapolyM) <- c("x","y")

ggplot(datapolyM, aes(x=x, y=y)) + 
  geom_polygon(fill="red", colour="black")

Export to pdf! You will see that the whole image is filled red!

Now lets turn the path of the star to run clockwise: Please respect the apply and reverse command in the second line:

star <- c(25.000,1.000,31.000,18.000,49.000,18.000,35.000,29.000,40.000,46.000,
          25.000,36.000,10.000,46.000,15.000,29.000,1.000,18.000,19.000,18.000) %>% matrix(ncol=2, byrow=T) %>% apply(2, rev)
star <- rbind(star,star[1,])
rim  <- c(0,0, 50,0, 50,50,0,50,0,0) %>% matrix(ncol=2, byrow=T)

datapolyM <- rbind(rim,star) %>% as.data.frame()
names(datapolyM) <- c("x","y")
datapolyM$id <- "a"

ggplot(datapolyM, aes(x=x, y=y)) + 
  geom_polygon(fill="red")

Now export to pdf again. You will see it worked this time! You have filled everything outside of a given polygon-shape!