PostGIS  3.7.0dev-r@@SVN_REVISION@@

◆ lw_dist3d_seg_seg()

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

Finds the two closest points on two linesegments.

Definition at line 1173 of file measures3d.c.

1174 {
1175  VECTOR3D v1, v2, vl;
1176  double s1k, s2k; /*two variables representing where on Line 1 (s1k) and where on Line 2 (s2k) a connecting line
1177  between the two lines is perpendicular to both lines*/
1178  POINT3DZ p1, p2;
1179  double a, b, c, d, e, D;
1180 
1181  /*s1p1 and s1p2 are the same point */
1182  if (p3dz_same(s1p1, s1p2))
1183  {
1184  return lw_dist3d_pt_seg(s1p1, s2p1, s2p2, dl);
1185  }
1186  /*s2p1 and s2p2 are the same point */
1187  if (p3dz_same(s2p1, s2p2))
1188  {
1189  dl->twisted = ((dl->twisted) * (-1));
1190  return lw_dist3d_pt_seg(s2p1, s1p1, s1p2, dl);
1191  }
1192  /*s2p1 and s1p1 are the same point */
1193  if (p3dz_same(s2p1, s1p1))
1194  {
1195  dl->distance = 0.0;
1196  dl->p1 = dl->p2 = *s2p1;
1197  return LW_TRUE;
1198  }
1199  /*
1200  Here we use algorithm from softsurfer.com
1201  that can be found here
1202  http://softsurfer.com/Archive/algorithm_0106/algorithm_0106.htm
1203  */
1204 
1205  if (!get_3dvector_from_points(s1p1, s1p2, &v1))
1206  return LW_FALSE;
1207 
1208  if (!get_3dvector_from_points(s2p1, s2p2, &v2))
1209  return LW_FALSE;
1210 
1211  if (!get_3dvector_from_points(s2p1, s1p1, &vl))
1212  return LW_FALSE;
1213 
1214  a = DOT(v1, v1);
1215  b = DOT(v1, v2);
1216  c = DOT(v2, v2);
1217  d = DOT(v1, vl);
1218  e = DOT(v2, vl);
1219  D = a * c - b * b;
1220 
1221  if (D < 0.000000001)
1222  { /* the lines are almost parallel*/
1223  s1k =
1224  0.0; /*If the lines are parallel we try by using the startpoint of first segment. If that gives a
1225  projected point on the second line outside segment 2 it will be found that s2k is >1 or <0.*/
1226  if (b > c) /* use the largest denominator*/
1227  s2k = d / b;
1228  else
1229  s2k = e / c;
1230  }
1231  else
1232  {
1233  s1k = (b * e - c * d) / D;
1234  s2k = (a * e - b * d) / D;
1235  }
1236 
1237  /* Now we check if the projected closest point on the infinite lines is outside our segments. If so the
1238  * combinations with start and end points will be tested*/
1239 
1240  if (s1k <= 0.0 || s1k >= 1.0 || s2k <= 0.0 || s2k >= 1.0)
1241  {
1242  if (s1k <= 0.0)
1243  {
1244  if (!lw_dist3d_pt_seg(s1p1, s2p1, s2p2, dl))
1245  return LW_FALSE;
1246  }
1247  if (s1k >= 1.0)
1248  {
1249  if (!lw_dist3d_pt_seg(s1p2, s2p1, s2p2, dl))
1250  return LW_FALSE;
1251  }
1252  if (s2k <= 0.0)
1253  {
1254  dl->twisted = ((dl->twisted) * (-1));
1255  if (!lw_dist3d_pt_seg(s2p1, s1p1, s1p2, dl))
1256  return LW_FALSE;
1257  }
1258  if (s2k >= 1.0)
1259  {
1260  dl->twisted = ((dl->twisted) * (-1));
1261  if (!lw_dist3d_pt_seg(s2p2, s1p1, s1p2, dl))
1262  return LW_FALSE;
1263  }
1264  }
1265  else
1266  { /*Find the closest point on the edges of both segments*/
1267  p1.x = s1p1->x + s1k * (s1p2->x - s1p1->x);
1268  p1.y = s1p1->y + s1k * (s1p2->y - s1p1->y);
1269  p1.z = s1p1->z + s1k * (s1p2->z - s1p1->z);
1270 
1271  p2.x = s2p1->x + s2k * (s2p2->x - s2p1->x);
1272  p2.y = s2p1->y + s2k * (s2p2->y - s2p1->y);
1273  p2.z = s2p1->z + s2k * (s2p2->z - s2p1->z);
1274 
1275  if (!lw_dist3d_pt_pt(&p1, &p2, dl)) /* Send the closest points to point-point calculation*/
1276  {
1277  return LW_FALSE;
1278  }
1279  }
1280  return LW_TRUE;
1281 }
#define LW_FALSE
Definition: liblwgeom.h:94
#define LW_TRUE
Return types for functions with status returns.
Definition: liblwgeom.h:93
int p3dz_same(const POINT3DZ *p1, const POINT3DZ *p2)
Definition: lwalgorithm.c:49
int lw_dist3d_pt_pt(const POINT3DZ *thep1, const 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:1082
static int get_3dvector_from_points(const POINT3DZ *p1, const POINT3DZ *p2, VECTOR3D *v)
Definition: measures3d.c:34
int lw_dist3d_pt_seg(const POINT3DZ *p, const POINT3DZ *A, const POINT3DZ *B, DISTPTS3D *dl)
If searching for min distance, this one finds the closest point on segment A-B from p.
Definition: measures3d.c:1026
#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:396
double x
Definition: liblwgeom.h:396
double y
Definition: liblwgeom.h:396

References DISTPTS3D::distance, DOT, get_3dvector_from_points(), lw_dist3d_pt_pt(), lw_dist3d_pt_seg(), LW_FALSE, LW_TRUE, DISTPTS3D::p1, DISTPTS3D::p2, p3dz_same(), 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: