Define a polygon label line segment

polygon_label_segment(
  x0,
  x1,
  y0,
  y1,
  sp,
  return_class = c("point", "matrix", "SpatialLines"),
  sp_buffer = 0,
  plot_debug = FALSE,
  relative = TRUE,
  verbose = FALSE,
  ...
)

Arguments

x0

numeric x-axis source position

x1

numeric x-axis target position

y0

numeric y-axis source position

y1

numeric y-axis target position

sp

sp::SpatialPolygons object representing the polygon

return_class

character string where "point" returns a matrix with one row containing the new target point; "matrix" contains two rows with source and new target points; "SpatialLines" returns sp::SpatialLines with the line segment from source to new target points.

sp_buffer

numeric indicating an optional buffer to use for the sp polygon. By default sp_buffer=0 uses no buffer, but a suggested buffer sp_buffer=-0.01 would make the polygon 1% smaller, therefore the line segment would be slightly inside the polygon border.

relative

logical indicating whether sp_buffer is scaled relative to the size of the polygon, see get_sp_buffer() for more details.

verbose

logical indicating whether to print verbose output, specifically describing which situation occurred.

...

additional arguments are passed to get_sp_buffer().

Value

numeric matrix with one row, representing the point of intersection with the polygon boundary, see comments above for exceptions. When return_class="matrix" then the matrix contains two rows, where the second row contains the point of intersection. When return_class="SpatialLines"

the object is sp::SpatialLines and represents the line from the first point and the point of intersection. Note that when there is no second point, the sp::SpatialLines object will only have one point.

Details

This function takes a line segment and polygon, and returns the point where a line segment starting at the source point touches the outer boundary of the polygon.

This function is intended to be used with polygon labels, where the original label position is inside the polygon, but is manually adjusted and may be placed somewhere outside the polygon. This function finds a suitable point to draw a line segment from the new label position to the polygon.

Some different situations are handled as follows, use verbose=TRUE to see which situation occurred.

  • When the starting point is outside the polygon, and end point is inside the polygon, this function finds the point where this line segment first intersects the polygon boundary. This is the driving reason for this function.

  • When the starting point is outside the polygon, and end point also outside the polygon, this function finds the nearest the nearest point along the polygon boundary.

  • When the starting point is inside the polygon, this function returns NULL.

Note that this function currently does not adjust for the size or position of a label.

Examples

x0 <- 0;x1 <- 1;y0 <- 0; y1 <- 1;
sp <- sp_ellipses(xcenter=1, ycenter=1, xradius=0.5, yradius=1)
sl2 <- polygon_label_segment(x0, x1, y0, y1, sp,
   return_class="SpatialLines",
   plot_debug=TRUE,
   main="segment drawn to boundary intersection");


# example of making a debug plot
lxy <- cbind(c(x0, x1), c(y0, y1));
sp <- sp_ellipses(xcenter=1, ycenter=1, xradius=0.5, yradius=1);
sl <- sp::SpatialLines(list(sp::Lines(list(sp::Line(lxy)), ID="a")));
sp::plot(sp, col="#00007777", border="blue3", lwd=2,
   xlim=c(0, 2), ylim=c(0, 2), asp=1,
   main="segment drawn to boundary intersection");
sp::plot(sl, lty="dotted", lwd=2, col="blue2", add=TRUE);
sp::plot(sl2, col="red3", lwd=4, add=TRUE)


# example where the line intersects multiple boundaries
x0 <- 0;x1 <- 2;y0 <- 0; y1 <- 2;
sl2 <- polygon_label_segment(x0, x1, y0, y1, sp,
   return_class="SpatialLines",
   plot_debug=TRUE,
   main="segment drawn to first boundary intersection");


# example where starting line does not intersect
x0 <- 0;x1 <- 1;y0 <- 0; y1 <- 1;
sp <- sp_ellipses(xcenter=2, ycenter=1, xradius=0.5, yradius=1);
sl2 <- polygon_label_segment(x0, x1, y0, y1, sp,
   return_class="SpatialLines",
   plot_debug=TRUE,
   main="segment drawn to nearest boundary point");


lxy <- cbind(c(x0, x1), c(y0, y1));
sp <- sp_ellipses(xcenter=2, ycenter=1, xradius=0.5, yradius=1);
sl <- sp::SpatialLines(list(sp::Lines(list(sp::Line(lxy)), ID="a")));
sl2 <- polygon_label_segment(x0, x1, y0, y1, sp, "SpatialLines"); 
sp::plot(sl, xlim=c(0, 3), ylim=c(0, 2), asp=1, lty="dotted",
   main="segment drawn to nearest boundary point");
sp::plot(sp, col="#00007777", border="navy", lwd=2, add=TRUE)
sp::plot(sl2, col="red", lwd=4, add=TRUE)


# example showing line fully inside the polygon
x0 <- 0;x1 <- 2;y0 <- 0; y1 <- 2;
sp <- sp_ellipses(xcenter=1, ycenter=1, xradius=1.5, yradius=2.2);
sl2 <- polygon_label_segment(x0, x1, y0, y1, sp,
   return_class="SpatialLines",
   plot_debug=TRUE,
   main="segment contained inside returns one point");


# example showing polygon with a hole inside
sp <- sp_ellipses(xcenter=1, ycenter=1, xradius=0.5, yradius=1);
sp_hole <- sp_ellipses(xcenter=1, ycenter=1, xradius=0.2, yradius=0.5);
sp_donut <- rgeos::gDifference(sp, sp_hole);
sl2 <- polygon_label_segment(x0, x1, y0, y1, sp_donut,
   return_class="SpatialLines",
   plot_debug=TRUE,
   main="segment drawn to first outer boundary intersection");


# example with line inside the polygon hole
x0 <- 0.9;x1 <- 1.1;y0 <- 0.9; y1 <- 1.1;
sp <- sp_ellipses(xcenter=1, ycenter=1, xradius=0.5, yradius=1);
sp_hole <- sp_ellipses(xcenter=1, ycenter=1, xradius=0.2, yradius=0.5);
sp_donut <- rgeos::gDifference(sp, sp_hole);
sl2 <- polygon_label_segment(x0, x1, y0, y1, sp_donut,
   return_class="SpatialLines",
   plot_debug=TRUE,
   main="segment drawn to nearest boundary");


# line crosses inside the polygon hole
x0 <- 1;x1 <- 1.4;y0 <- 1; y1 <- 1.4;
sp <- sp_ellipses(xcenter=1, ycenter=1, xradius=0.5, yradius=1);
sp_hole <- sp_ellipses(xcenter=1, ycenter=1, xradius=0.2, yradius=0.5);
sp_donut <- rgeos::gDifference(sp, sp_hole);
sl2 <- polygon_label_segment(x0, x1, y0, y1, sp_donut,
   return_class="SpatialLines",
   plot_debug=TRUE,
   main="segment drawn to boundary intersection");


x0 <- 0.6;x1 <- 1;y0 <- 0.6; y1 <- 1;
sp <- sp_ellipses(xcenter=1, ycenter=1, xradius=0.5, yradius=1);
sp_hole <- sp_ellipses(xcenter=1, ycenter=1, xradius=0.2, yradius=0.5);
sp_donut <- rgeos::gDifference(sp, sp_hole);
sl2 <- polygon_label_segment(x0, x1, y0, y1, sp_donut,
   return_class="SpatialLines",
   plot_debug=TRUE,
   main="first point inside the polygon, returns one point");


# example showing multiple input points
x0 <- c(0.6, 1.1);
x1 <- c(1, 1.4);
y0 <- c(0.6, 1.1);
y1 <- c(1, 1.4);
sl2 <- polygon_label_segment(x0, x1, y0, y1, sp=sp_donut,
   return_class="point", verbose=TRUE, plot_debug=TRUE); 
#> ##  (18:07:05) 07Jul2023:   polygon_label_segment(): j:1, spi[j]:1 

#> ##  (18:07:05) 07Jul2023:   polygon_label_segment(): The first point is inside the polygon. 
#> ##  (18:07:05) 07Jul2023:   polygon_label_segment(): j:2, spi[j]:1 
#> ##  (18:07:05) 07Jul2023:   polygon_label_segment(): The first point is outside the polygon. 
#> ##  (18:07:05) 07Jul2023:   polygon_label_segment(): Using first outer line segment 1 

# example showing sp_buffer
sl2 <- polygon_label_segment(x0, x1, y0, y1, sp=sp_donut,
   sp_buffer=-0.1,
   return_class="point", verbose=TRUE, plot_debug=TRUE); 
#> ##  (18:07:05) 07Jul2023:   polygon_label_segment(): j:1, spi[j]:1 

#> ##  (18:07:05) 07Jul2023:   polygon_label_segment(): Applied sp_buffer:-0.1 
#> ##  (18:07:05) 07Jul2023:   polygon_label_segment(): The first point is inside the polygon. 
#> ##  (18:07:05) 07Jul2023:   polygon_label_segment(): j:2, spi[j]:1 
#> ##  (18:07:05) 07Jul2023:   polygon_label_segment(): Applied sp_buffer:-0.1 
#> ##  (18:07:05) 07Jul2023:   polygon_label_segment(): The first point is outside the polygon. 
#> ##  (18:07:05) 07Jul2023:   polygon_label_segment(): Using first outer line segment 1