我的情节有来自原点的两条光线.我想以逆时针方向遮蔽从光线1到光线2的区域.我想我可能不得不使用geom_polygon.我希望能够为任意两条任意射线做到这一点,但我似乎无法弄明白.
*我想坚持使用笛卡尔坐标.
这是我的意思的一个例子:
d <- data.frame()
base <- ggplot(d) + xlim(-5, 5) + ylim(-5, 5) + geom_blank()
ray1 <- geom_segment(aes(x=0,y=0,xend=5,yend=4))
ray2 <- geom_segment(aes(x=0,y=0,xend=0,yend=5))
shading <- geom_polygon(data=data.frame(x=c(0,5,5,0), y=c(0,4,5,5)),
aes(x,y), fill="blue", alpha=0.2)
base + ray1 + ray2 + shading
Run Code Online (Sandbox Code Playgroud)
对于这个例子,我能够通过检查获得多边形的顶点,但是我将生成几个随机的光线对,我不想每次都手动完成这个过程.

有什么建议?
这可能有点儿马车和笨重.我想看看更聪明的人提供更优雅的解决方案
但是我不清楚你想如何处理边缘.看例子
shade_segs <- function(ray1, ray2, xlim = c(-5, 5), ylim = xlim) {
ray <- data.frame(x = c(ray1[1], pmin(ray1[3], xlim[2]),
pmin(ray1[3], ylim[2]), ray2[3]),
y = c(ray2[1], ray1[4],
## how to handle the edges? :
pmin(ray2[4], xlim[2]), pmin(ray2[4], ylim[2])))
# pmin(ray1[4], xlim[2]), pmin(ray2[4], ylim[2])))
# print(ray)
require(ggplot2)
ggplot() + xlim(xlim[1], xlim[2]) + ylim(ylim[1], ylim[2]) +
geom_segment(aes_string(x = ray1[1], y = ray1[2],
xend = ray1[3], yend = ray1[4])) +
geom_segment(aes_string(x = ray2[1], y = ray2[2],
xend = ray2[3], yend = ray2[4])) +
geom_polygon(data = ray, aes(x = x, y = y), fill = "blue", alpha = 0.2) +
theme_bw()
}
library(gridExtra)
## c(x0, y0, x1, y1)
l <- list(shade_segs(ray1 = c(0, 0, 5, 4),
ray2 = c(0, 0, 0, 5)),
shade_segs(ray1 = c(0, 0, 2.5, 2.5),
ray2 = c(0, 0, 1, 5)),
shade_segs(ray1 = c(0, 0, -1, 5),
ray2 = c(0, 0, -.5, 5)),
shade_segs(ray1 = c(0, 0, -3, 5),
ray2 = c(0, 0, -.5, -5)))
(do.call(arrangeGrob, c(l, list(nrow = 2, ncol = 2))))
Run Code Online (Sandbox Code Playgroud)

或者像这样:
shade_segs <- function(ray1, ray2, xlim = c(-5, 5), ylim = xlim) {
ray <- data.frame(x = c(ray1[1], pmin(ray1[3], xlim[2]),
pmin(ray1[3], ylim[2]), ray2[3]),
y = c(ray2[1], ray1[4],
## how to handle the edges? :
# pmin(ray2[4], xlim[2]), pmin(ray2[4], ylim[2])))
pmin(ray1[4], xlim[2]), pmin(ray2[4], ylim[2])))
# print(ray)
require(ggplot2)
ggplot() + xlim(xlim[1], xlim[2]) + ylim(ylim[1], ylim[2]) +
geom_segment(aes_string(x = ray1[1], y = ray1[2],
xend = ray1[3], yend = ray1[4])) +
geom_segment(aes_string(x = ray2[1], y = ray2[2],
xend = ray2[3], yend = ray2[4])) +
geom_polygon(data = ray, aes(x = x, y = y), fill = "blue", alpha = 0.2) +
theme_bw()
}
library(gridExtra)
## c(x0, y0, x1, y1)
l <- list(shade_segs(ray1 = c(0, 0, 5, 4),
ray2 = c(0, 0, 0, 5)),
shade_segs(ray1 = c(0, 0, 2.5, 2.5),
ray2 = c(0, 0, 1, 5)),
shade_segs(ray1 = c(0, 0, -1, 5),
ray2 = c(0, 0, -.5, 5)),
shade_segs(ray1 = c(0, 0, -3, 5),
ray2 = c(0, 0, -.5, -5)))
(do.call(arrangeGrob, c(l, list(nrow = 2, ncol = 2))))
Run Code Online (Sandbox Code Playgroud)

第二个对我来说更有意义.
我觉得它会更简单; 但我已经到了这个丑陋的解决方案.这是一个辅助函数,用于计算沿着定义的界限的所有交点base
findslice<-function(seg1, seg2, base=NULL, lim=getlims(base)) {
getlims<-function(x) {
list(y=x$scales$get_scales("y")$limits,
x=x$scales$get_scales("x")$limits)
}
gethit<-function(seg, lim) {
with(seg$mapping, {
x<-eval(x); y<-eval(y);
xend<-eval(xend); yend<-eval(yend);
dx<-(xend-x); dy<-(yend-y)
bx<-ifelse(dx>0,max(lim$x), min(lim$x))
by<-ifelse(dy>0,max(lim$y), min(lim$y))
sx<-ifelse(dx>0,1, 3)
sy<-ifelse(dy>0,2, 4)
if(identical(dx,0)) {
return(list(x=x,y=by, side=sy))
}
if (identical(dy,0)) {
return(list(x=bx,y=y, side=sx))
}
nx<-bx
ny<-(y+dy)*(nx-x)/dx
side<-sx
if (abs(ny)>abs(by)) {
ny<-by
nx<-(x+dx)*(ny-y)/dy
side<-sy
}
return(list(x=nx, y=ny, side=side))
})
}
p1<-gethit(seg1, lim)
p2<-gethit(seg2, lim)
side<-p1$side
corners<-data.frame(x=lim$x[c(2,1,1,2)], y=lim$y[c(2,2,1,1)])
r<-data.frame(x=c(seg1$mapping$x, p1$x), y=c(seg1$mapping$y, p1$y))
while(side != p2$side) {
r<-rbind(r, corners[side, ])
side <- (side %% 4) +1
}
r<-rbind(r, data.frame(x=p2$x, y=p2$y))
r
}
Run Code Online (Sandbox Code Playgroud)
这将创建多边形绘图所需的data.frame.例如
base <- ggplot(d) + xlim(-5, 5) + ylim(-5, 5) + geom_blank()
ray1 <- geom_segment(aes(x=0,y=0,xend=5,yend=4))
ray2 <- geom_segment(aes(x=0,y=0,xend=0,yend=5))
shading <- geom_polygon(data=findslice(ray1, ray2, base),
aes(x,y), fill="blue", alpha=0.2)
base + ray1 + ray2 + shading + ggtitle("Take 1")
Run Code Online (Sandbox Code Playgroud)
这个想法是它将超出限制,然后开始环绕边缘.另一个例子是
ray1 <- geom_segment(aes(x=0,y=0,xend=5,yend=4))
ray2 <- geom_segment(aes(x=0,y=0,xend=0,yend=5))
shading <- geom_polygon(data=findslice(ray1, ray2, base),
aes(x,y), fill="blue", alpha=0.2)
base + ray1 + ray2 + shading + ggtitle("Take 2")
Run Code Online (Sandbox Code Playgroud)

所以这里有两种方法可以做到这一点.第一种使用蛮力方法,这种方法虽然速度很慢但最简单.第二个使用包中的功能集sp和rgeos操作地图几何.这在概念上类似于使用凸壳的解决方案.
第一种方法:
r1 <- data.frame(x=c(0,5),y=c(0,4))
r2 <- data.frame(x=c(0,0),y=c(0,5))
th1 <- with(r1,atan2(y[2],x[2]))
th2 <- with(r2,atan2(y[2],x[2]))
is.between <- function(x,lo,hi) {
if (lo<=hi) return(x>=lo & x<=hi)
return(!(x<lo & x>hi))
}
df <- expand.grid(x=seq(-5,5,len=200),y=seq(-5,5,len=200))
df$th <- atan2(df$y,df$x)
library(ggplot2)
ggplot(mapping=aes(x,y))+
xlim(-5,5) + ylim(-5,5)+
geom_tile(data=df[is.between(df$th,th1,th2),],fill="blue",alpha=.2)+
geom_line(data=r1)+
geom_line(data=r2)
Run Code Online (Sandbox Code Playgroud)

这种方法认识到,由于你的光线从原点开始,我们可以创建一个覆盖整个空间的瓷砖网格,然后只是在两条光线扫过的角度之间与x轴形成一个角度.下面的代码以逆时针方式对"之间" r1和"之间"区域r2进行着色.因此,如果r2是第一位的,这将灯罩外部角度(尝试交换的定义r1和r2).请注意,我们正在使用geom_tile(...)阴影.
用你的形式主义:
base <- ggplot() + xlim(-5,5) + ylim(-5,5) + geom_blank()
ray1 <- geom_line(data=r1, aes(x,y))
ray2 <- geom_line(data=r2, aes(x,y))
shading <- geom_tile(data=df[is.between(df$th,th1,th2),],aes(x,y),
fill="blue",alpha=.2)
base + ray1 + ray2 + shading
Run Code Online (Sandbox Code Playgroud)
第二种方法:
library(sp) # for SpatialPolygons(...), etc.
library(rgeos) # for gIntersection(...)
th1 <- with(r1,atan2(y[2],x[2]))
th1 <- ifelse(th1>0, th1, 2*pi+th1)
th2 <- with(r2,atan2(y[2],x[2]))
th2 <- ifelse(th2>0, th2, 2*pi+th2)
th <- if(th1<th2){seq(th1,th2,length=100)} else {c(seq(th1,2*pi,length=100),seq(0,th2,length=100))}
df <- data.frame(x=c(0,5*sqrt(2)*cos(th),0),y=c(0,5*sqrt(2)*sin(th),0))
slice <- SpatialPolygons(list(Polygons(list(Polygon(df)),"1")))
box <- readWKT("POLYGON((-5 -5,-5 5,5 5,5 -5,-5 -5))")
shade <- gIntersection(box,slice)
sh.df <- as.data.frame(shade@polygons[[1]]@Polygons[[1]]@coords)
base <- ggplot() + xlim(-5,5) + ylim(-5,5) + geom_blank()
ray1 <- geom_line(data=r1, aes(x,y))
ray2 <- geom_line(data=r2, aes(x,y))
shading <- geom_polygon(data=sh.df,aes(x,y),fill="blue",alpha=.2)
base + ray1 + ray2 + shading
Run Code Online (Sandbox Code Playgroud)

这种方法利用了特征集rgeos,特别是计算SpatialPolygons交集的能力.它创建了两个SpatialPolygons:一个叫做box简单地覆盖从(-5,-5)到(5,5)的区域,另一个叫做slice两个射线之间的扇形切片.我们必须使用一个半径作为饼,5*sqrt(2)以保证切片至少延伸到角落box.然后我们计算FO使用这两个多边形的交点gIntersection(...)在rgeos包装,并使用ggplot绘制它为多边形.
虽然创建多边形的语法是曲折的,但这种方法要快得多.