PostGIS  3.3.9dev-r@@SVN_REVISION@@

◆ lw_dist3d_seg_seg()

int lw_dist3d_seg_seg ( POINT3DZ s1p1,
POINT3DZ s1p2,
POINT3DZ s2p1,
POINT3DZ s2p2,
DISTPTS3D dl 
)

Finds the two closest points on two linesegments.

Definition at line 1139 of file measures3d.c.

1140 {
1141  VECTOR3D v1, v2, vl;
1142  double s1k, s2k; /*two variables representing where on Line 1 (s1k) and where on Line 2 (s2k) a connecting line
1143  between the two lines is perpendicular to both lines*/
1144  POINT3DZ p1, p2;
1145  double a, b, c, d, e, D;
1146 
1147  /*s1p1 and s1p2 are the same point */
1148  if ((s1p1->x == s1p2->x) && (s1p1->y == s1p2->y) && (s1p1->z == s1p2->z))
1149  {
1150  return lw_dist3d_pt_seg(s1p1, s2p1, s2p2, dl);
1151  }
1152  /*s2p1 and s2p2 are the same point */
1153  if ((s2p1->x == s2p2->x) && (s2p1->y == s2p2->y) && (s2p1->z == s2p2->z))
1154  {
1155  dl->twisted = ((dl->twisted) * (-1));
1156  return lw_dist3d_pt_seg(s2p1, s1p1, s1p2, dl);
1157  }
1158  /*s2p1 and s1p1 are the same point */
1159  if ((s2p1->x == s1p1->x) && (s2p1->y == s1p1->y) && (s2p1->z == s1p1->z))
1160  {
1161  dl->distance = 0.0;
1162  dl->p1 = dl->p2 = *s2p1;
1163  return LW_TRUE;
1164  }
1165 
1166  /*
1167  Here we use algorithm from softsurfer.com
1168  that can be found here
1169  http://softsurfer.com/Archive/algorithm_0106/algorithm_0106.htm
1170  */
1171 
1172  if (!get_3dvector_from_points(s1p1, s1p2, &v1))
1173  return LW_FALSE;
1174 
1175  if (!get_3dvector_from_points(s2p1, s2p2, &v2))
1176  return LW_FALSE;
1177 
1178  if (!get_3dvector_from_points(s2p1, s1p1, &vl))
1179  return LW_FALSE;
1180 
1181  a = DOT(v1, v1);
1182  b = DOT(v1, v2);
1183  c = DOT(v2, v2);
1184  d = DOT(v1, vl);
1185  e = DOT(v2, vl);
1186  D = a * c - b * b;
1187 
1188  if (D < 0.000000001)
1189  { /* the lines are almost parallel*/
1190  s1k =
1191  0.0; /*If the lines are parallel we try by using the startpoint of first segment. If that gives a
1192  projected point on the second line outside segment 2 it wil be found that s2k is >1 or <0.*/
1193  if (b > c) /* use the largest denominator*/
1194  s2k = d / b;
1195  else
1196  s2k = e / c;
1197  }
1198  else
1199  {
1200  s1k = (b * e - c * d) / D;
1201  s2k = (a * e - b * d) / D;
1202  }
1203 
1204  /* Now we check if the projected closest point on the infinite lines is outside our segments. If so the
1205  * combinations with start and end points will be tested*/
1206 
1207  if (s1k <= 0.0 || s1k >= 1.0 || s2k <= 0.0 || s2k >= 1.0)
1208  {
1209  if (s1k <= 0.0)
1210  {
1211  if (!lw_dist3d_pt_seg(s1p1, s2p1, s2p2, dl))
1212  return LW_FALSE;
1213  }
1214  if (s1k >= 1.0)
1215  {
1216  if (!lw_dist3d_pt_seg(s1p2, s2p1, s2p2, dl))
1217  return LW_FALSE;
1218  }
1219  if (s2k <= 0.0)
1220  {
1221  dl->twisted = ((dl->twisted) * (-1));
1222  if (!lw_dist3d_pt_seg(s2p1, s1p1, s1p2, dl))
1223  return LW_FALSE;
1224  }
1225  if (s2k >= 1.0)
1226  {
1227  dl->twisted = ((dl->twisted) * (-1));
1228  if (!lw_dist3d_pt_seg(s2p2, s1p1, s1p2, dl))
1229  return LW_FALSE;
1230  }
1231  }
1232  else
1233  { /*Find the closest point on the edges of both segments*/
1234  p1.x = s1p1->x + s1k * (s1p2->x - s1p1->x);
1235  p1.y = s1p1->y + s1k * (s1p2->y - s1p1->y);
1236  p1.z = s1p1->z + s1k * (s1p2->z - s1p1->z);
1237 
1238  p2.x = s2p1->x + s2k * (s2p2->x - s2p1->x);
1239  p2.y = s2p1->y + s2k * (s2p2->y - s2p1->y);
1240  p2.z = s2p1->z + s2k * (s2p2->z - s2p1->z);
1241 
1242  if (!lw_dist3d_pt_pt(&p1, &p2, dl)) /* Send the closest points to point-point calculation*/
1243  {
1244  return LW_FALSE;
1245  }
1246  }
1247  return LW_TRUE;
1248 }
#define LW_FALSE
Definition: liblwgeom.h:109
#define LW_TRUE
Return types for functions with status returns.
Definition: liblwgeom.h:108
static int get_3dvector_from_points(POINT3DZ *p1, POINT3DZ *p2, VECTOR3D *v)
Definition: measures3d.c:34
int lw_dist3d_pt_pt(POINT3DZ *thep1, POINT3DZ *thep2, DISTPTS3D *dl)
Compares incoming points and stores the points closest to each other or most far away from each other...
Definition: measures3d.c:1048
int lw_dist3d_pt_seg(POINT3DZ *p, POINT3DZ *A, POINT3DZ *B, DISTPTS3D *dl)
If searching for min distance, this one finds the closest point on segment A-B from p.
Definition: measures3d.c:992
#define DOT(u, v)
Definition: measures3d.h:31
POINT3DZ p2
Definition: measures3d.h:42
int twisted
Definition: measures3d.h:45
POINT3DZ p1
Definition: measures3d.h:41
double distance
Definition: measures3d.h:40
double z
Definition: liblwgeom.h:411
double x
Definition: liblwgeom.h:411
double y
Definition: liblwgeom.h:411

References DISTPTS3D::distance, DOT, get_3dvector_from_points(), lw_dist3d_pt_pt(), lw_dist3d_pt_seg(), LW_FALSE, LW_TRUE, DISTPTS3D::p1, DISTPTS3D::p2, DISTPTS3D::twisted, POINT3DZ::x, POINT3DZ::y, and POINT3DZ::z.

Referenced by lw_dist3d_ptarray_ptarray().

Here is the call graph for this function:
Here is the caller graph for this function: