rlinear-algebratrigonometrypythagorean

Calculate total distance from point to reference point along line


Problem: I need to calculate the distance (a+b) from all points on the graph to the midpoint point (green dot) along the slope of the line through both centroids (red and blue squares). I can calculate the direct distance (c) between individual points (red and blue dots) and the midpoint (green dot) via:

library(tidyverse)
library(raster)

df1 %>%
  mutate(distance = raster::pointDistance(cbind(midpoint_x, midpoint_y),
                                          cbind(x, y),
                                          lonlat = F))

            x           y group midpoint_x midpoint_y blue_centroid_x blue_centroid_y red_centroid_x red_centroid_y   distance
1   0.8113613  -3.5439179  Blue  0.1562366  0.1435983      -0.2556599      -0.2349791       0.568133      0.5221758  3.7452588
2   1.4434981   4.2093381   Red  0.1562366  0.1435983      -0.2556599      -0.2349791       0.568133      0.5221758  4.2646550
3   1.2309291  -0.2878122   Red  0.1562366  0.1435983      -0.2556599      -0.2349791       0.568133      0.5221758  1.1580497
4  -1.9098897  -3.3308182  Blue  0.1562366  0.1435983      -0.2556599      -0.2349791       0.568133      0.5221758  4.0423320
5   0.6985894   3.6461840  Blue  0.1562366  0.1435983      -0.2556599      -0.2349791       0.568133      0.5221758  3.5443269
6  -2.0363846   3.4571756  Blue  0.1562366  0.1435983      -0.2556599      -0.2349791       0.568133      0.5221758  3.9733339

However, I need the sum of a and b. The angle between points and the line/slope will always be 90 degrees.


Plot

enter image description here

# Calculate slope of line between the two centroids
line_slope <- (unique(df1$blue_centroid_y)-unique(df1$red_centroid_y))/(unique(df1$blue_centroid_x)-unique(df1$red_centroid_x))

# Plot all data
ggplot(data = df1, aes(x = x, y = y, color = group)) + 
  geom_point(alpha = 0.5, size = 2) +                      # All points (red and blue) to be used in calculations
  geom_abline(slope = line_slope) +                        # Black slope line
  geom_point(inherit.aes = FALSE, 
             aes(x = midpoint_x, y = midpoint_y), 
             color = "green", 
             size = 5) +                                   # Center point to be used as reference
  geom_point(inherit.aes = FALSE, 
             aes(x = blue_centroid_x, y = blue_centroid_y), 
             color = "blue", 
             fill = "white", 
             size = 4, 
             shape = 7) +                                  # Blue centroid
  geom_point(inherit.aes = FALSE, 
             aes(x = red_centroid_x, y = red_centroid_y), 
             color = "red", 
             size = 4, 
             shape = 7) +                                  # Red centroid
  theme_bw() +
  scale_color_manual(values = c("blue", "red")) +
  xlim(c(-6, 6))+
  ylim(c(-6, 6))

Data:

dput(df1)

structure(list(x = c(0.811361331853275, 1.44349809543412, 1.23092914355961, 
-1.90988970973443, 0.69858942646712, -2.03638457481904, 2.1058829412788, 
0.221006034690947, 3.73319145750774, -0.933799307513561, 4.9301534877275, 
2.43085617522765, -0.105238204065442, 1.06217911466733, -0.935978548040991, 
1.45588579923626, -1.59250057170202, 1.69050030950508, 0.610813794082633, 
-0.407606568002722), y = c(-3.54391785329915, 4.20933811061919, 
-0.287812209357956, -3.33081817835282, 3.64618404692162, 3.45717559066226, 
3.51906607809147, 3.86260103874712, -4.67007307930421, -1.60232511734553, 
1.55929339656666, 4.46131511839878, 0.596967304721319, 2.26528856056295, 
2.2598922029041, 2.9660813965289, -13.3321818554433, 4.14815043766351, 
3.77469822821531, -1.8194038691507), group = c("Blue", "Red", 
"Red", "Blue", "Blue", "Blue", "Blue", "Blue", "Blue", "Blue", 
"Red", "Red", "Blue", "Red", "Blue", "Red", "Blue", "Red", "Red", 
"Blue"), midpoint_x = c(0.1562366, 0.1562366, 0.1562366, 0.1562366, 
0.1562366, 0.1562366, 0.1562366, 0.1562366, 0.1562366, 0.1562366, 
0.1562366, 0.1562366, 0.1562366, 0.1562366, 0.1562366, 0.1562366, 
0.1562366, 0.1562366, 0.1562366, 0.1562366), midpoint_y = c(0.1435983, 
0.1435983, 0.1435983, 0.1435983, 0.1435983, 0.1435983, 0.1435983, 
0.1435983, 0.1435983, 0.1435983, 0.1435983, 0.1435983, 0.1435983, 
0.1435983, 0.1435983, 0.1435983, 0.1435983, 0.1435983, 0.1435983, 
0.1435983), blue_centroid_x = c(-0.2556599, -0.2556599, -0.2556599, 
-0.2556599, -0.2556599, -0.2556599, -0.2556599, -0.2556599, -0.2556599, 
-0.2556599, -0.2556599, -0.2556599, -0.2556599, -0.2556599, -0.2556599, 
-0.2556599, -0.2556599, -0.2556599, -0.2556599, -0.2556599), 
    blue_centroid_y = c(-0.2349791, -0.2349791, -0.2349791, -0.2349791, 
    -0.2349791, -0.2349791, -0.2349791, -0.2349791, -0.2349791, 
    -0.2349791, -0.2349791, -0.2349791, -0.2349791, -0.2349791, 
    -0.2349791, -0.2349791, -0.2349791, -0.2349791, -0.2349791, 
    -0.2349791), red_centroid_x = c(0.568133, 0.568133, 0.568133, 
    0.568133, 0.568133, 0.568133, 0.568133, 0.568133, 0.568133, 
    0.568133, 0.568133, 0.568133, 0.568133, 0.568133, 0.568133, 
    0.568133, 0.568133, 0.568133, 0.568133, 0.568133), red_centroid_y = c(0.5221758, 
    0.5221758, 0.5221758, 0.5221758, 0.5221758, 0.5221758, 0.5221758, 
    0.5221758, 0.5221758, 0.5221758, 0.5221758, 0.5221758, 0.5221758, 
    0.5221758, 0.5221758, 0.5221758, 0.5221758, 0.5221758, 0.5221758, 
    0.5221758)), row.names = c("1", "2", "3", "4", "5", "6", 
"7", "8", "9", "10", "11", "12", "13", "14", "15", "16", "17", 
"18", "19", "20"), class = "data.frame")


Solution

  • My trig's a little rusty, but I believe this gives you what you want:

    library(raster)
    library(dplyr)
    
    df1 %>% 
      mutate(
        # slope of line between centroids
        line_slope = (blue_centroid_y - red_centroid_y) / (blue_centroid_x - red_centroid_x),
        # slopes of lines between each point and midpoint
        c_slope = (midpoint_y - y) / (midpoint_x - x),
        # angles between c_slope and line_slope
        c_angle = atan(abs((line_slope - c_slope) / (1 + line_slope * c_slope))),
        # distance between each point and midpoint
        c_distance = pointDistance(cbind(midpoint_x, midpoint_y), cbind(x, y), lonlat = F),
        # distance along opposite side = hypoteneuse * sin(angle)
        a_distance = c_distance * sin(c_angle),
        # distance along adjacent side = hypoteneuse * cos(angle)
        b_distance = c_distance * cos(c_angle),
        ab_distance = a_distance + b_distance,
      ) %>% 
      dplyr::select(!line_slope:b_distance)
    
    #             x           y group midpoint_x midpoint_y blue_centroid_x blue_centroid_y red_centroid_x red_centroid_y ab_distance
    # 1   0.8113613  -3.5439179  Blue  0.1562366  0.1435983      -0.2556599      -0.2349791       0.568133      0.5221758   5.1712915
    # 2   1.4434981   4.2093381   Red  0.1562366  0.1435983      -0.2556599      -0.2349791       0.568133      0.5221758   5.8213890
    # 3   1.2309291  -0.2878122   Red  0.1562366  0.1435983      -0.2556599      -0.2349791       0.568133      0.5221758   1.5441900
    # 4  -1.9098897  -3.3308182  Blue  0.1562366  0.1435983      -0.2556599      -0.2349791       0.568133      0.5221758   5.0322604
    # 5   0.6985894   3.6461840  Blue  0.1562366  0.1435983      -0.2556599      -0.2349791       0.568133      0.5221758   4.9813108
    # 6  -2.0363846   3.4571756  Blue  0.1562366  0.1435983      -0.2556599      -0.2349791       0.568133      0.5221758   4.5513623
    # 7   2.1058829   3.5190661  Blue  0.1562366  0.1435983      -0.2556599      -0.2349791       0.568133      0.5221758   4.8855127
    # 8   0.2210060   3.8626010  Blue  0.1562366  0.1435983      -0.2556599      -0.2349791       0.568133      0.5221758   5.2586556
    # 9   3.7331915  -4.6700731  Blue  0.1562366  0.1435983      -0.2556599      -0.2349791       0.568133      0.5221758   6.5884867
    # 10 -0.9337993  -1.6023251  Blue  0.1562366  0.1435983      -0.2556599      -0.2349791       0.568133      0.5221758   2.5318375
    # 11  4.9301535   1.5592934   Red  0.1562366  0.1435983      -0.2556599      -0.2349791       0.568133      0.5221758   6.6610337
    # 12  2.4308562   4.4613151   Red  0.1562366  0.1435983      -0.2556599      -0.2349791       0.568133      0.5221758   6.2362264
    # 13 -0.1052382   0.5969673  Blue  0.1562366  0.1435983      -0.2556599      -0.2349791       0.568133      0.5221758   0.6250191
    # 14  1.0621791   2.2652886   Red  0.1562366  0.1435983      -0.2556599      -0.2349791       0.568133      0.5221758   3.0518166
    # 15 -0.9359785   2.2598922  Blue  0.1562366  0.1435983      -0.2556599      -0.2349791       0.568133      0.5221758   2.9251871
    # 16  1.4558858   2.9660814   Red  0.1562366  0.1435983      -0.2556599      -0.2349791       0.568133      0.5221758   4.0654561
    # 17 -1.5925006 -13.3321819  Blue  0.1562366  0.1435983      -0.2556599      -0.2349791       0.568133      0.5221758  19.1448738
    # 18  1.6905003   4.1481504   Red  0.1562366  0.1435983      -0.2556599      -0.2349791       0.568133      0.5221758   5.7496441
    # 19  0.6108138   3.7746982   Red  0.1562366  0.1435983      -0.2556599      -0.2349791       0.568133      0.5221758   5.1576684
    # 20 -0.4076066  -1.8194039  Blue  0.1562366  0.1435983      -0.2556599      -0.2349791       0.568133      0.5221758   2.8072223