geo_ops.c
上传用户:blenddy
上传日期:2007-01-07
资源大小:6495k
文件大小:93k
源码类别:

数据库系统

开发平台:

Unix_Linux

  1. /*-------------------------------------------------------------------------
  2.  *
  3.  * geo_ops.c
  4.  *   2D geometric operations
  5.  *
  6.  * Copyright (c) 1994, Regents of the University of California
  7.  *
  8.  *
  9.  * IDENTIFICATION
  10.  *   $Header: /usr/local/cvsroot/pgsql/src/backend/utils/adt/geo_ops.c,v 1.41.2.1 1999/08/02 05:24:52 scrappy Exp $
  11.  *
  12.  *-------------------------------------------------------------------------
  13.  */
  14. #include <math.h>
  15. #include <limits.h>
  16. #include <float.h>
  17. #include <ctype.h>
  18. #include "postgres.h"
  19. #include "utils/geo_decls.h"
  20. #ifndef PI
  21. #define PI 3.1415926536
  22. #endif
  23. /*
  24.  * Internal routines
  25.  */
  26. static int point_inside(Point *p, int npts, Point *plist);
  27. static int lseg_crossing(double x, double y, double px, double py);
  28. static BOX *box_construct(double x1, double x2, double y1, double y2);
  29. static BOX *box_copy(BOX *box);
  30. static BOX *box_fill(BOX *result, double x1, double x2, double y1, double y2);
  31. static double box_ht(BOX *box);
  32. static double box_wd(BOX *box);
  33. static double circle_ar(CIRCLE *circle);
  34. static CIRCLE *circle_copy(CIRCLE *circle);
  35. static LINE *line_construct_pm(Point *pt, double m);
  36. static double lseg_dt(LSEG *l1, LSEG *l2);
  37. static void make_bound_box(POLYGON *poly);
  38. static PATH *path_copy(PATH *path);
  39. static bool plist_same(int npts, Point *p1, Point *p2);
  40. static Point *point_construct(double x, double y);
  41. static Point *point_copy(Point *pt);
  42. static int single_decode(char *str, float8 *x, char **ss);
  43. static int single_encode(float8 x, char *str);
  44. static int pair_decode(char *str, float8 *x, float8 *y, char **s);
  45. static int pair_encode(float8 x, float8 y, char *str);
  46. static int pair_count(char *s, char delim);
  47. static int path_decode(int opentype, int npts, char *str, int *isopen, char **ss, Point *p);
  48. static char *path_encode(bool closed, int npts, Point *pt);
  49. static void statlseg_construct(LSEG *lseg, Point *pt1, Point *pt2);
  50. static double box_ar(BOX *box);
  51. static Point *interpt_sl(LSEG *lseg, LINE *line);
  52. /*
  53.  * Delimiters for input and output strings.
  54.  * LDELIM, RDELIM, and DELIM are left, right, and separator delimiters, respectively.
  55.  * LDELIM_EP, RDELIM_EP are left and right delimiters for paths with endpoints.
  56.  */
  57. #define LDELIM '('
  58. #define RDELIM ')'
  59. #define DELIM ','
  60. #define LDELIM_EP '['
  61. #define RDELIM_EP ']'
  62. #define LDELIM_C '<'
  63. #define RDELIM_C '>'
  64. /* Maximum number of output digits printed */
  65. #define P_MAXDIG DBL_DIG
  66. #define P_MAXLEN (2*(P_MAXDIG+7)+1)
  67. static int digits8 = P_MAXDIG;
  68. /*
  69.  * Geometric data types are composed of points.
  70.  * This code tries to support a common format throughout the data types,
  71.  * to allow for more predictable usage and data type conversion.
  72.  * The fundamental unit is the point. Other units are line segments,
  73.  * open paths, boxes, closed paths, and polygons (which should be considered
  74.  * non-intersecting closed paths).
  75.  *
  76.  * Data representation is as follows:
  77.  * point: (x,y)
  78.  * line segment: [(x1,y1),(x2,y2)]
  79.  * box: (x1,y1),(x2,y2)
  80.  * open path: [(x1,y1),...,(xn,yn)]
  81.  * closed path: ((x1,y1),...,(xn,yn))
  82.  * polygon: ((x1,y1),...,(xn,yn))
  83.  *
  84.  * For boxes, the points are opposite corners with the first point at the top right.
  85.  * For closed paths and polygons, the points should be reordered to allow
  86.  * fast and correct equality comparisons.
  87.  *
  88.  * XXX perhaps points in complex shapes should be reordered internally
  89.  * to allow faster internal operations, but should keep track of input order
  90.  * and restore that order for text output - tgl 97/01/16
  91.  */
  92. static int
  93. single_decode(char *str, float8 *x, char **s)
  94. {
  95. char    *cp;
  96. if (!PointerIsValid(str))
  97. return FALSE;
  98. while (isspace(*str))
  99. str++;
  100. *x = strtod(str, &cp);
  101. #ifdef GEODEBUG
  102. fprintf(stderr, "single_decode- (%x) try decoding %s to %gn", (cp - str), str, *x);
  103. #endif
  104. if (cp <= str)
  105. return FALSE;
  106. while (isspace(*cp))
  107. cp++;
  108. if (s != NULL)
  109. *s = cp;
  110. return TRUE;
  111. } /* single_decode() */
  112. static int
  113. single_encode(float8 x, char *str)
  114. {
  115. sprintf(str, "%.*g", digits8, x);
  116. return TRUE;
  117. } /* single_encode() */
  118. static int
  119. pair_decode(char *str, float8 *x, float8 *y, char **s)
  120. {
  121. int has_delim;
  122. char    *cp;
  123. if (!PointerIsValid(str))
  124. return FALSE;
  125. while (isspace(*str))
  126. str++;
  127. if ((has_delim = (*str == LDELIM)))
  128. str++;
  129. while (isspace(*str))
  130. str++;
  131. *x = strtod(str, &cp);
  132. if (cp <= str)
  133. return FALSE;
  134. while (isspace(*cp))
  135. cp++;
  136. if (*cp++ != DELIM)
  137. return FALSE;
  138. while (isspace(*cp))
  139. cp++;
  140. *y = strtod(cp, &str);
  141. if (str <= cp)
  142. return FALSE;
  143. while (isspace(*str))
  144. str++;
  145. if (has_delim)
  146. {
  147. if (*str != RDELIM)
  148. return FALSE;
  149. str++;
  150. while (isspace(*str))
  151. str++;
  152. }
  153. if (s != NULL)
  154. *s = str;
  155. return TRUE;
  156. }
  157. static int
  158. pair_encode(float8 x, float8 y, char *str)
  159. {
  160. sprintf(str, "%.*g,%.*g", digits8, x, digits8, y);
  161. return TRUE;
  162. }
  163. static int
  164. path_decode(int opentype, int npts, char *str, int *isopen, char **ss, Point *p)
  165. {
  166. int depth = 0;
  167. char    *s,
  168.    *cp;
  169. int i;
  170. s = str;
  171. while (isspace(*s))
  172. s++;
  173. if ((*isopen = (*s == LDELIM_EP)))
  174. {
  175. /* no open delimiter allowed? */
  176. if (!opentype)
  177. return FALSE;
  178. depth++;
  179. s++;
  180. while (isspace(*s))
  181. s++;
  182. }
  183. else if (*s == LDELIM)
  184. {
  185. cp = (s + 1);
  186. while (isspace(*cp))
  187. cp++;
  188. if (*cp == LDELIM)
  189. {
  190. #ifdef NOT_USED
  191. /* nested delimiters with only one point? */
  192. if (npts <= 1)
  193. return FALSE;
  194. #endif
  195. depth++;
  196. s = cp;
  197. }
  198. else if (strrchr(s, LDELIM) == s)
  199. {
  200. depth++;
  201. s = cp;
  202. }
  203. }
  204. for (i = 0; i < npts; i++)
  205. {
  206. if (!pair_decode(s, &(p->x), &(p->y), &s))
  207. return FALSE;
  208. if (*s == DELIM)
  209. s++;
  210. p++;
  211. }
  212. while (depth > 0)
  213. {
  214. if ((*s == RDELIM)
  215. || ((*s == RDELIM_EP) && (*isopen) && (depth == 1)))
  216. {
  217. depth--;
  218. s++;
  219. while (isspace(*s))
  220. s++;
  221. }
  222. else
  223. return FALSE;
  224. }
  225. *ss = s;
  226. return TRUE;
  227. } /* path_decode() */
  228. static char *
  229. path_encode(bool closed, int npts, Point *pt)
  230. {
  231. char    *result = palloc(npts * (P_MAXLEN + 3) + 2);
  232. char    *cp;
  233. int i;
  234. cp = result;
  235. switch (closed)
  236. {
  237. case TRUE:
  238. *cp++ = LDELIM;
  239. break;
  240. case FALSE:
  241. *cp++ = LDELIM_EP;
  242. break;
  243. default:
  244. break;
  245. }
  246. for (i = 0; i < npts; i++)
  247. {
  248. *cp++ = LDELIM;
  249. if (!pair_encode(pt->x, pt->y, cp))
  250. elog(ERROR, "Unable to format path", NULL);
  251. cp += strlen(cp);
  252. *cp++ = RDELIM;
  253. *cp++ = DELIM;
  254. pt++;
  255. }
  256. cp--;
  257. switch (closed)
  258. {
  259. case TRUE:
  260. *cp++ = RDELIM;
  261. break;
  262. case FALSE:
  263. *cp++ = RDELIM_EP;
  264. break;
  265. default:
  266. break;
  267. }
  268. *cp = '';
  269. return result;
  270. } /* path_encode() */
  271. /*-------------------------------------------------------------
  272.  * pair_count - count the number of points
  273.  * allow the following notation:
  274.  * '((1,2),(3,4))'
  275.  * '(1,3,2,4)'
  276.  * require an odd number of delim characters in the string
  277.  *-------------------------------------------------------------*/
  278. static int
  279. pair_count(char *s, char delim)
  280. {
  281. int ndelim = 0;
  282. while ((s = strchr(s, delim)) != NULL)
  283. {
  284. ndelim++;
  285. s++;
  286. }
  287. return (ndelim % 2) ? ((ndelim + 1) / 2) : -1;
  288. }
  289. /***********************************************************************
  290.  **
  291.  ** Routines for two-dimensional boxes.
  292.  **
  293.  ***********************************************************************/
  294. /*----------------------------------------------------------
  295.  * Formatting and conversion routines.
  296.  *---------------------------------------------------------*/
  297. /* box_in - convert a string to internal form.
  298.  *
  299.  * External format: (two corners of box)
  300.  * "(f8, f8), (f8, f8)"
  301.  * also supports the older style "(f8, f8, f8, f8)"
  302.  */
  303. BOX *
  304. box_in(char *str)
  305. {
  306. BOX    *box = palloc(sizeof(BOX));
  307. int isopen;
  308. char    *s;
  309. double x,
  310. y;
  311. if (!PointerIsValid(str))
  312. elog(ERROR, " Bad (null) box external representation", NULL);
  313. if ((!path_decode(FALSE, 2, str, &isopen, &s, &(box->high)))
  314. || (*s != ''))
  315. elog(ERROR, "Bad box external representation '%s'", str);
  316. /* reorder corners if necessary... */
  317. if (box->high.x < box->low.x)
  318. {
  319. x = box->high.x;
  320. box->high.x = box->low.x;
  321. box->low.x = x;
  322. }
  323. if (box->high.y < box->low.y)
  324. {
  325. y = box->high.y;
  326. box->high.y = box->low.y;
  327. box->low.y = y;
  328. }
  329. return box;
  330. } /* box_in() */
  331. /* box_out - convert a box to external form.
  332.  */
  333. char *
  334. box_out(BOX *box)
  335. {
  336. if (!PointerIsValid(box))
  337. return NULL;
  338. return path_encode(-1, 2, (Point *) &(box->high));
  339. } /* box_out() */
  340. /* box_construct - fill in a new box.
  341.  */
  342. static BOX *
  343. box_construct(double x1, double x2, double y1, double y2)
  344. {
  345. BOX    *result = palloc(sizeof(BOX));
  346. return box_fill(result, x1, x2, y1, y2);
  347. }
  348. /* box_fill - fill in a static box
  349.  */
  350. static BOX *
  351. box_fill(BOX *result, double x1, double x2, double y1, double y2)
  352. {
  353. if (x1 > x2)
  354. {
  355. result->high.x = x1;
  356. result->low.x = x2;
  357. }
  358. else
  359. {
  360. result->high.x = x2;
  361. result->low.x = x1;
  362. }
  363. if (y1 > y2)
  364. {
  365. result->high.y = y1;
  366. result->low.y = y2;
  367. }
  368. else
  369. {
  370. result->high.y = y2;
  371. result->low.y = y1;
  372. }
  373. return result;
  374. }
  375. /* box_copy - copy a box
  376.  */
  377. static BOX *
  378. box_copy(BOX *box)
  379. {
  380. BOX    *result = palloc(sizeof(BOX));
  381. memmove((char *) result, (char *) box, sizeof(BOX));
  382. return result;
  383. }
  384. /*----------------------------------------------------------
  385.  * Relational operators for BOXes.
  386.  * <, >, <=, >=, and == are based on box area.
  387.  *---------------------------------------------------------*/
  388. /* box_same - are two boxes identical?
  389.  */
  390. bool
  391. box_same(BOX *box1, BOX *box2)
  392. {
  393. return ((FPeq(box1->high.x, box2->high.x) && FPeq(box1->low.x, box2->low.x)) &&
  394. (FPeq(box1->high.y, box2->high.y) && FPeq(box1->low.y, box2->low.y)));
  395. }
  396. /* box_overlap - does box1 overlap box2?
  397.  */
  398. bool
  399. box_overlap(BOX *box1, BOX *box2)
  400. {
  401. return (((FPge(box1->high.x, box2->high.x) && FPle(box1->low.x, box2->high.x)) ||
  402.  (FPge(box2->high.x, box1->high.x) && FPle(box2->low.x, box1->high.x))) &&
  403. ((FPge(box1->high.y, box2->high.y) && FPle(box1->low.y, box2->high.y)) ||
  404.  (FPge(box2->high.y, box1->high.y) && FPle(box2->low.y, box1->high.y))));
  405. }
  406. /* box_overleft - is the right edge of box1 to the left of
  407.  * the right edge of box2?
  408.  *
  409.  * This is "less than or equal" for the end of a time range,
  410.  * when time ranges are stored as rectangles.
  411.  */
  412. bool
  413. box_overleft(BOX *box1, BOX *box2)
  414. {
  415. return FPle(box1->high.x, box2->high.x);
  416. }
  417. /* box_left - is box1 strictly left of box2?
  418.  */
  419. bool
  420. box_left(BOX *box1, BOX *box2)
  421. {
  422. return FPlt(box1->high.x, box2->low.x);
  423. }
  424. /* box_right - is box1 strictly right of box2?
  425.  */
  426. bool
  427. box_right(BOX *box1, BOX *box2)
  428. {
  429. return FPgt(box1->low.x, box2->high.x);
  430. }
  431. /* box_overright - is the left edge of box1 to the right of
  432.  * the left edge of box2?
  433.  *
  434.  * This is "greater than or equal" for time ranges, when time ranges
  435.  * are stored as rectangles.
  436.  */
  437. bool
  438. box_overright(BOX *box1, BOX *box2)
  439. {
  440. return box1->low.x >= box2->low.x;
  441. }
  442. /* box_contained - is box1 contained by box2?
  443.  */
  444. bool
  445. box_contained(BOX *box1, BOX *box2)
  446. {
  447. return ((FPle(box1->high.x, box2->high.x) && FPge(box1->low.x, box2->low.x)) &&
  448. (FPle(box1->high.y, box2->high.y) && FPge(box1->low.y, box2->low.y)));
  449. }
  450. /* box_contain - does box1 contain box2?
  451.  */
  452. bool
  453. box_contain(BOX *box1, BOX *box2)
  454. {
  455. return ((FPge(box1->high.x, box2->high.x) && FPle(box1->low.x, box2->low.x) &&
  456. FPge(box1->high.y, box2->high.y) && FPle(box1->low.y, box2->low.y)));
  457. }
  458. /* box_positionop -
  459.  * is box1 entirely {above,below} box2?
  460.  */
  461. bool
  462. box_below(BOX *box1, BOX *box2)
  463. {
  464. return FPle(box1->high.y, box2->low.y);
  465. }
  466. bool
  467. box_above(BOX *box1, BOX *box2)
  468. {
  469. return FPge(box1->low.y, box2->high.y);
  470. }
  471. /* box_relop - is area(box1) relop area(box2), within
  472.  * our accuracy constraint?
  473.  */
  474. bool
  475. box_lt(BOX *box1, BOX *box2)
  476. {
  477. return FPlt(box_ar(box1), box_ar(box2));
  478. }
  479. bool
  480. box_gt(BOX *box1, BOX *box2)
  481. {
  482. return FPgt(box_ar(box1), box_ar(box2));
  483. }
  484. bool
  485. box_eq(BOX *box1, BOX *box2)
  486. {
  487. return FPeq(box_ar(box1), box_ar(box2));
  488. }
  489. bool
  490. box_le(BOX *box1, BOX *box2)
  491. {
  492. return FPle(box_ar(box1), box_ar(box2));
  493. }
  494. bool
  495. box_ge(BOX *box1, BOX *box2)
  496. {
  497. return FPge(box_ar(box1), box_ar(box2));
  498. }
  499. /*----------------------------------------------------------
  500.  * "Arithmetic" operators on boxes.
  501.  * box_foo returns foo as an object (pointer) that
  502.  can be passed between languages.
  503.  * box_xx is an internal routine which returns the
  504.  * actual value (and cannot be handed back to
  505.  * LISP).
  506.  *---------------------------------------------------------*/
  507. /* box_area - returns the area of the box.
  508.  */
  509. double *
  510. box_area(BOX *box)
  511. {
  512. double    *result = palloc(sizeof(double));
  513. *result = box_wd(box) * box_ht(box);
  514. return result;
  515. }
  516. /* box_width - returns the width of the box
  517.  *   (horizontal magnitude).
  518.  */
  519. double *
  520. box_width(BOX *box)
  521. {
  522. double    *result = palloc(sizeof(double));
  523. *result = box->high.x - box->low.x;
  524. return result;
  525. } /* box_width() */
  526. /* box_height - returns the height of the box
  527.  *   (vertical magnitude).
  528.  */
  529. double *
  530. box_height(BOX *box)
  531. {
  532. double    *result = palloc(sizeof(double));
  533. *result = box->high.y - box->low.y;
  534. return result;
  535. }
  536. /* box_distance - returns the distance between the
  537.  *   center points of two boxes.
  538.  */
  539. double *
  540. box_distance(BOX *box1, BOX *box2)
  541. {
  542. double    *result = palloc(sizeof(double));
  543. Point    *a,
  544.    *b;
  545. a = box_center(box1);
  546. b = box_center(box2);
  547. *result = HYPOT(a->x - b->x, a->y - b->y);
  548. pfree(a);
  549. pfree(b);
  550. return result;
  551. }
  552. /* box_center - returns the center point of the box.
  553.  */
  554. Point *
  555. box_center(BOX *box)
  556. {
  557. Point    *result = palloc(sizeof(Point));
  558. result->x = (box->high.x + box->low.x) / 2.0;
  559. result->y = (box->high.y + box->low.y) / 2.0;
  560. return result;
  561. }
  562. /* box_ar - returns the area of the box.
  563.  */
  564. static double
  565. box_ar(BOX *box)
  566. {
  567. return box_wd(box) * box_ht(box);
  568. }
  569. /* box_wd - returns the width (length) of the box
  570.  *   (horizontal magnitude).
  571.  */
  572. static double
  573. box_wd(BOX *box)
  574. {
  575. return box->high.x - box->low.x;
  576. }
  577. /* box_ht - returns the height of the box
  578.  *   (vertical magnitude).
  579.  */
  580. static double
  581. box_ht(BOX *box)
  582. {
  583. return box->high.y - box->low.y;
  584. }
  585. /* box_dt - returns the distance between the
  586.  *   center points of two boxes.
  587.  */
  588. #ifdef NOT_USED
  589. static double
  590. box_dt(BOX *box1, BOX *box2)
  591. {
  592. double result;
  593. Point    *a,
  594.    *b;
  595. a = box_center(box1);
  596. b = box_center(box2);
  597. result = HYPOT(a->x - b->x, a->y - b->y);
  598. pfree(a);
  599. pfree(b);
  600. return result;
  601. }
  602. #endif
  603. /*----------------------------------------------------------
  604.  * Funky operations.
  605.  *---------------------------------------------------------*/
  606. /* box_intersect -
  607.  * returns the overlapping portion of two boxes,
  608.  *   or NULL if they do not intersect.
  609.  */
  610. BOX *
  611. box_intersect(BOX *box1, BOX *box2)
  612. {
  613. BOX    *result;
  614. if (!box_overlap(box1, box2))
  615. return NULL;
  616. result = palloc(sizeof(BOX));
  617. result->high.x = Min(box1->high.x, box2->high.x);
  618. result->low.x = Max(box1->low.x, box2->low.x);
  619. result->high.y = Min(box1->high.y, box2->high.y);
  620. result->low.y = Max(box1->low.y, box2->low.y);
  621. return result;
  622. }
  623. /* box_diagonal -
  624.  * returns a line segment which happens to be the
  625.  *   positive-slope diagonal of "box".
  626.  * provided, of course, we have LSEGs.
  627.  */
  628. LSEG *
  629. box_diagonal(BOX *box)
  630. {
  631. Point p1,
  632. p2;
  633. p1.x = box->high.x;
  634. p1.y = box->high.y;
  635. p2.x = box->low.x;
  636. p2.y = box->low.y;
  637. return lseg_construct(&p1, &p2);
  638. }
  639. /***********************************************************************
  640.  **
  641.  ** Routines for 2D lines.
  642.  ** Lines are not intended to be used as ADTs per se,
  643.  ** but their ops are useful tools for other ADT ops.  Thus,
  644.  ** there are few relops.
  645.  **
  646.  ***********************************************************************/
  647. LINE *
  648. line_in(char *str)
  649. {
  650. LINE    *line;
  651. #ifdef ENABLE_LINE_TYPE
  652. LSEG lseg;
  653. int isopen;
  654. char    *s;
  655. #endif
  656. if (!PointerIsValid(str))
  657. elog(ERROR, " Bad (null) line external representation", NULL);
  658. #ifdef ENABLE_LINE_TYPE
  659. if ((!path_decode(TRUE, 2, str, &isopen, &s, &(lseg.p[0])))
  660. || (*s != ''))
  661. elog(ERROR, "Bad line external representation '%s'", str);
  662. line = line_construct_pp(&(lseg.p[0]), &(lseg.p[1]));
  663. #else
  664. elog(ERROR, "line not yet implemented");
  665. line = NULL;
  666. #endif
  667. return line;
  668. } /* line_in() */
  669. char *
  670. line_out(LINE *line)
  671. {
  672. char    *result;
  673. #ifdef ENABLE_LINE_TYPE
  674. LSEG lseg;
  675. #endif
  676. if (!PointerIsValid(line))
  677. return NULL;
  678. #ifdef ENABLE_LINE_TYPE
  679. if (FPzero(line->B))
  680. { /* vertical */
  681. /* use "x = C" */
  682. result->A = -1;
  683. result->B = 0;
  684. result->C = pt1->x;
  685. #ifdef GEODEBUG
  686. printf("line_construct_pp- line is verticaln");
  687. #endif
  688. #ifdef NOT_USED
  689. result->m = DBL_MAX;
  690. #endif
  691. }
  692. else if (FPzero(line->A))
  693. { /* horizontal */
  694. /* use "x = C" */
  695. result->A = 0;
  696. result->B = -1;
  697. result->C = pt1->y;
  698. #ifdef GEODEBUG
  699. printf("line_construct_pp- line is horizontaln");
  700. #endif
  701. #ifdef NOT_USED
  702. result->m = 0.0;
  703. #endif
  704. }
  705. else
  706. {
  707. }
  708. if (line_horizontal(line))
  709. {
  710. }
  711. else if (line_vertical(line))
  712. {
  713. }
  714. else
  715. {
  716. }
  717. return path_encode(TRUE, 2, (Point *) &(ls->p[0]));
  718. #else
  719. elog(ERROR, "line not yet implemented");
  720. result = NULL;
  721. #endif
  722. return result;
  723. } /* line_out() */
  724. /*----------------------------------------------------------
  725.  * Conversion routines from one line formula to internal.
  726.  * Internal form: Ax+By+C=0
  727.  *---------------------------------------------------------*/
  728. /* line_construct_pm()
  729.  * point-slope
  730.  */
  731. static LINE *
  732. line_construct_pm(Point *pt, double m)
  733. {
  734. LINE    *result = palloc(sizeof(LINE));
  735. /* use "mx - y + yinter = 0" */
  736. result->A = m;
  737. result->B = -1.0;
  738. result->C = pt->y - m * pt->x;
  739. #ifdef NOT_USED
  740. result->m = m;
  741. #endif
  742. return result;
  743. } /* line_construct_pm() */
  744. /* line_construct_pp()
  745.  * two points
  746.  */
  747. LINE *
  748. line_construct_pp(Point *pt1, Point *pt2)
  749. {
  750. LINE    *result = palloc(sizeof(LINE));
  751. if (FPeq(pt1->x, pt2->x))
  752. { /* vertical */
  753. /* use "x = C" */
  754. result->A = -1;
  755. result->B = 0;
  756. result->C = pt1->x;
  757. #ifdef GEODEBUG
  758. printf("line_construct_pp- line is verticaln");
  759. #endif
  760. #ifdef NOT_USED
  761. result->m = DBL_MAX;
  762. #endif
  763. }
  764. else if (FPeq(pt1->y, pt2->y))
  765. { /* horizontal */
  766. /* use "x = C" */
  767. result->A = 0;
  768. result->B = -1;
  769. result->C = pt1->y;
  770. #ifdef GEODEBUG
  771. printf("line_construct_pp- line is horizontaln");
  772. #endif
  773. #ifdef NOT_USED
  774. result->m = 0.0;
  775. #endif
  776. }
  777. else
  778. {
  779. /* use "mx - y + yinter = 0" */
  780. #ifdef NOT_USED
  781. result->A = (pt1->y - pt2->y) / (pt1->x - pt2->x);
  782. #endif
  783. result->A = (pt2->y - pt1->y) / (pt2->x - pt1->x);
  784. result->B = -1.0;
  785. result->C = pt1->y - result->A * pt1->x;
  786. #ifdef GEODEBUG
  787. printf("line_construct_pp- line is neither vertical nor horizontal (diffs x=%.*g, y=%.*gn",
  788.    digits8, (pt2->x - pt1->x), digits8, (pt2->y - pt1->y));
  789. #endif
  790. #ifdef NOT_USED
  791. result->m = result->A;
  792. #endif
  793. }
  794. return result;
  795. } /* line_construct_pp() */
  796. /*----------------------------------------------------------
  797.  * Relative position routines.
  798.  *---------------------------------------------------------*/
  799. bool
  800. line_intersect(LINE *l1, LINE *l2)
  801. {
  802. return !line_parallel(l1, l2);
  803. }
  804. bool
  805. line_parallel(LINE *l1, LINE *l2)
  806. {
  807. #ifdef NOT_USED
  808. return FPeq(l1->m, l2->m);
  809. #endif
  810. if (FPzero(l1->B))
  811. return FPzero(l2->B);
  812. return FPeq(l2->A, l1->A * (l2->B / l1->B));
  813. } /* line_parallel() */
  814. bool
  815. line_perp(LINE *l1, LINE *l2)
  816. {
  817. #ifdef NOT_USED
  818. if (l1->m)
  819. return FPeq(l2->m / l1->m, -1.0);
  820. else if (l2->m)
  821. return FPeq(l1->m / l2->m, -1.0);
  822. #endif
  823. if (FPzero(l1->A))
  824. return FPzero(l2->B);
  825. else if (FPzero(l1->B))
  826. return FPzero(l2->A);
  827. return FPeq(((l1->A * l2->B) / (l1->B * l2->A)), -1.0);
  828. } /* line_perp() */
  829. bool
  830. line_vertical(LINE *line)
  831. {
  832. #ifdef NOT_USED
  833. return FPeq(line->A, -1.0) && FPzero(line->B);
  834. #endif
  835. return FPzero(line->B);
  836. } /* line_vertical() */
  837. bool
  838. line_horizontal(LINE *line)
  839. {
  840. #ifdef NOT_USED
  841. return FPzero(line->m);
  842. #endif
  843. return FPzero(line->A);
  844. } /* line_horizontal() */
  845. bool
  846. line_eq(LINE *l1, LINE *l2)
  847. {
  848. double k;
  849. if (!FPzero(l2->A))
  850. k = l1->A / l2->A;
  851. else if (!FPzero(l2->B))
  852. k = l1->B / l2->B;
  853. else if (!FPzero(l2->C))
  854. k = l1->C / l2->C;
  855. else
  856. k = 1.0;
  857. return (FPeq(l1->A, k * l2->A) &&
  858. FPeq(l1->B, k * l2->B) &&
  859. FPeq(l1->C, k * l2->C));
  860. }
  861. /*----------------------------------------------------------
  862.  * Line arithmetic routines.
  863.  *---------------------------------------------------------*/
  864. /* line_distance()
  865.  * Distance between two lines.
  866.  */
  867. double *
  868. line_distance(LINE *l1, LINE *l2)
  869. {
  870. double    *result = palloc(sizeof(double));
  871. Point    *tmp;
  872. if (line_intersect(l1, l2))
  873. {
  874. *result = 0.0;
  875. return result;
  876. }
  877. if (line_vertical(l1))
  878. *result = fabs(l1->C - l2->C);
  879. else
  880. {
  881. tmp = point_construct(0.0, l1->C);
  882. result = dist_pl(tmp, l2);
  883. pfree(tmp);
  884. }
  885. return result;
  886. }
  887. /* line_interpt()
  888.  * Point where two lines l1, l2 intersect (if any)
  889.  */
  890. Point *
  891. line_interpt(LINE *l1, LINE *l2)
  892. {
  893. Point    *result;
  894. double x,
  895. y;
  896. if (line_parallel(l1, l2))
  897. return NULL;
  898. #ifdef NOT_USED
  899. if (line_vertical(l1))
  900. result = point_construct(l2->m * l1->C + l2->C, l1->C);
  901. else if (line_vertical(l2))
  902. result = point_construct(l1->m * l2->C + l1->C, l2->C);
  903. else
  904. {
  905. x = (l1->C - l2->C) / (l2->A - l1->A);
  906. result = point_construct(x, l1->m * x + l1->C);
  907. }
  908. #endif
  909. if (line_vertical(l1))
  910. {
  911. #ifdef NOT_USED
  912. x = l1->C;
  913. y = -((l2->A * x + l2->C) / l2->B);
  914. #endif
  915. x = l1->C;
  916. y = (l2->A * x + l2->C);
  917. }
  918. else if (line_vertical(l2))
  919. {
  920. #ifdef NOT_USED
  921. x = l2->C;
  922. y = -((l1->A * x + l1->C) / l1->B);
  923. #endif
  924. x = l2->C;
  925. y = (l1->A * x + l1->C);
  926. }
  927. else
  928. {
  929. #ifdef NOT_USED
  930. x = (l2->B * l1->C - l1->B * l2->C) / (l2->A * l1->B - l1->A * l2->B);
  931. y = -((l1->A * x + l1->C) / l1->B);
  932. #endif
  933. x = (l1->C - l2->C) / (l2->A - l1->A);
  934. y = (l1->A * x + l1->C);
  935. }
  936. result = point_construct(x, y);
  937. #ifdef GEODEBUG
  938. printf("line_interpt- lines are A=%.*g, B=%.*g, C=%.*g, A=%.*g, B=%.*g, C=%.*gn",
  939.    digits8, l1->A, digits8, l1->B, digits8, l1->C, digits8, l2->A, digits8, l2->B, digits8, l2->C);
  940. printf("line_interpt- lines intersect at (%.*g,%.*g)n", digits8, x, digits8, y);
  941. #endif
  942. return result;
  943. } /* line_interpt() */
  944. /***********************************************************************
  945.  **
  946.  ** Routines for 2D paths (sequences of line segments, also
  947.  ** called `polylines').
  948.  **
  949.  ** This is not a general package for geometric paths,
  950.  ** which of course include polygons; the emphasis here
  951.  ** is on (for example) usefulness in wire layout.
  952.  **
  953.  ***********************************************************************/
  954. /*----------------------------------------------------------
  955.  * String to path / path to string conversion.
  956.  * External format:
  957.  * "((xcoord, ycoord),... )"
  958.  * "[(xcoord, ycoord),... ]"
  959.  * "(xcoord, ycoord),... "
  960.  * "[xcoord, ycoord,... ]"
  961.  * Also support older format:
  962.  * "(closed, npts, xcoord, ycoord,... )"
  963.  *---------------------------------------------------------*/
  964. PATH *
  965. path_in(char *str)
  966. {
  967. PATH    *path;
  968. int isopen;
  969. char    *s;
  970. int npts;
  971. int size;
  972. int depth = 0;
  973. if (!PointerIsValid(str))
  974. elog(ERROR, "Bad (null) path external representation");
  975. if ((npts = pair_count(str, ',')) <= 0)
  976. elog(ERROR, "Bad path external representation '%s'", str);
  977. s = str;
  978. while (isspace(*s))
  979. s++;
  980. /* skip single leading paren */
  981. if ((*s == LDELIM) && (strrchr(s, LDELIM) == s))
  982. {
  983. s++;
  984. depth++;
  985. }
  986. size = offsetof(PATH, p[0]) +(sizeof(path->p[0]) * npts);
  987. path = palloc(size);
  988. path->size = size;
  989. path->npts = npts;
  990. if ((!path_decode(TRUE, npts, s, &isopen, &s, &(path->p[0])))
  991. && (!((depth == 0) && (*s == ''))) && !((depth >= 1) && (*s == RDELIM)))
  992. elog(ERROR, "Bad path external representation '%s'", str);
  993. path->closed = (!isopen);
  994. return path;
  995. } /* path_in() */
  996. char *
  997. path_out(PATH *path)
  998. {
  999. if (!PointerIsValid(path))
  1000. return NULL;
  1001. return path_encode(path->closed, path->npts, (Point *) &(path->p[0]));
  1002. } /* path_out() */
  1003. /*----------------------------------------------------------
  1004.  * Relational operators.
  1005.  * These are based on the path cardinality,
  1006.  * as stupid as that sounds.
  1007.  *
  1008.  * Better relops and access methods coming soon.
  1009.  *---------------------------------------------------------*/
  1010. bool
  1011. path_n_lt(PATH *p1, PATH *p2)
  1012. {
  1013. return (p1->npts < p2->npts);
  1014. }
  1015. bool
  1016. path_n_gt(PATH *p1, PATH *p2)
  1017. {
  1018. return (p1->npts > p2->npts);
  1019. }
  1020. bool
  1021. path_n_eq(PATH *p1, PATH *p2)
  1022. {
  1023. return (p1->npts == p2->npts);
  1024. }
  1025. bool
  1026. path_n_le(PATH *p1, PATH *p2)
  1027. {
  1028. return (p1->npts <= p2->npts);
  1029. }
  1030. bool
  1031. path_n_ge(PATH *p1, PATH *p2)
  1032. {
  1033. return (p1->npts >= p2->npts);
  1034. }
  1035. /*----------------------------------------------------------
  1036.  * Conversion operators.
  1037.  *---------------------------------------------------------*/
  1038. bool
  1039. path_isclosed(PATH *path)
  1040. {
  1041. if (!PointerIsValid(path))
  1042. return FALSE;
  1043. return path->closed;
  1044. } /* path_isclosed() */
  1045. bool
  1046. path_isopen(PATH *path)
  1047. {
  1048. if (!PointerIsValid(path))
  1049. return FALSE;
  1050. return !path->closed;
  1051. } /* path_isopen() */
  1052. int4
  1053. path_npoints(PATH *path)
  1054. {
  1055. if (!PointerIsValid(path))
  1056. return 0;
  1057. return path->npts;
  1058. } /* path_npoints() */
  1059. PATH *
  1060. path_close(PATH *path)
  1061. {
  1062. PATH    *result;
  1063. if (!PointerIsValid(path))
  1064. return NULL;
  1065. result = path_copy(path);
  1066. result->closed = TRUE;
  1067. return result;
  1068. } /* path_close() */
  1069. PATH *
  1070. path_open(PATH *path)
  1071. {
  1072. PATH    *result;
  1073. if (!PointerIsValid(path))
  1074. return NULL;
  1075. result = path_copy(path);
  1076. result->closed = FALSE;
  1077. return result;
  1078. } /* path_open() */
  1079. static PATH *
  1080. path_copy(PATH *path)
  1081. {
  1082. PATH    *result;
  1083. int size;
  1084. size = offsetof(PATH, p[0]) +(sizeof(path->p[0]) * path->npts);
  1085. result = palloc(size);
  1086. memmove((char *) result, (char *) path, size);
  1087. return result;
  1088. } /* path_copy() */
  1089. /* path_inter -
  1090.  * Does p1 intersect p2 at any point?
  1091.  * Use bounding boxes for a quick (O(n)) check, then do a
  1092.  * O(n^2) iterative edge check.
  1093.  */
  1094. bool
  1095. path_inter(PATH *p1, PATH *p2)
  1096. {
  1097. BOX b1,
  1098. b2;
  1099. int i,
  1100. j;
  1101. LSEG seg1,
  1102. seg2;
  1103. b1.high.x = b1.low.x = p1->p[0].x;
  1104. b1.high.y = b1.low.y = p1->p[0].y;
  1105. for (i = 1; i < p1->npts; i++)
  1106. {
  1107. b1.high.x = Max(p1->p[i].x, b1.high.x);
  1108. b1.high.y = Max(p1->p[i].y, b1.high.y);
  1109. b1.low.x = Min(p1->p[i].x, b1.low.x);
  1110. b1.low.y = Min(p1->p[i].y, b1.low.y);
  1111. }
  1112. b2.high.x = b2.low.x = p2->p[0].x;
  1113. b2.high.y = b2.low.y = p2->p[0].y;
  1114. for (i = 1; i < p2->npts; i++)
  1115. {
  1116. b2.high.x = Max(p2->p[i].x, b2.high.x);
  1117. b2.high.y = Max(p2->p[i].y, b2.high.y);
  1118. b2.low.x = Min(p2->p[i].x, b2.low.x);
  1119. b2.low.y = Min(p2->p[i].y, b2.low.y);
  1120. }
  1121. if (!box_overlap(&b1, &b2))
  1122. return FALSE;
  1123. /* pairwise check lseg intersections */
  1124. for (i = 0; i < p1->npts - 1; i++)
  1125. {
  1126. for (j = 0; j < p2->npts - 1; j++)
  1127. {
  1128. statlseg_construct(&seg1, &p1->p[i], &p1->p[i + 1]);
  1129. statlseg_construct(&seg2, &p2->p[j], &p2->p[j + 1]);
  1130. if (lseg_intersect(&seg1, &seg2))
  1131. return TRUE;
  1132. }
  1133. }
  1134. /* if we dropped through, no two segs intersected */
  1135. return FALSE;
  1136. } /* path_inter() */
  1137. /* path_distance()
  1138.  * This essentially does a cartesian product of the lsegs in the
  1139.  * two paths, and finds the min distance between any two lsegs
  1140.  */
  1141. double *
  1142. path_distance(PATH *p1, PATH *p2)
  1143. {
  1144. double    *min = NULL,
  1145.    *tmp;
  1146. int i,
  1147. j;
  1148. LSEG seg1,
  1149. seg2;
  1150. /*
  1151. statlseg_construct(&seg1, &p1->p[0], &p1->p[1]);
  1152. statlseg_construct(&seg2, &p2->p[0], &p2->p[1]);
  1153. min = lseg_distance(&seg1, &seg2);
  1154. */
  1155. for (i = 0; i < p1->npts - 1; i++)
  1156. for (j = 0; j < p2->npts - 1; j++)
  1157. {
  1158. statlseg_construct(&seg1, &p1->p[i], &p1->p[i + 1]);
  1159. statlseg_construct(&seg2, &p2->p[j], &p2->p[j + 1]);
  1160. tmp = lseg_distance(&seg1, &seg2);
  1161. if ((min == NULL) || (*min < *tmp))
  1162. {
  1163. if (min != NULL)
  1164. pfree(min);
  1165. min = tmp;
  1166. }
  1167. else
  1168. pfree(tmp);
  1169. }
  1170. return min;
  1171. } /* path_distance() */
  1172. /*----------------------------------------------------------
  1173.  * "Arithmetic" operations.
  1174.  *---------------------------------------------------------*/
  1175. double *
  1176. path_length(PATH *path)
  1177. {
  1178. double    *result;
  1179. int i;
  1180. result = palloc(sizeof(double));
  1181. *result = 0;
  1182. for (i = 0; i < (path->npts - 1); i++)
  1183. *result += point_dt(&path->p[i], &path->p[i + 1]);
  1184. return result;
  1185. } /* path_length() */
  1186. #ifdef NOT_USED
  1187. double
  1188. path_ln(PATH *path)
  1189. {
  1190. double result;
  1191. int i;
  1192. result = 0;
  1193. for (i = 0; i < (path->npts - 1); i++)
  1194. result += point_dt(&path->p[i], &path->p[i + 1]);
  1195. return result;
  1196. } /* path_ln() */
  1197. #endif
  1198. /***********************************************************************
  1199.  **
  1200.  ** Routines for 2D points.
  1201.  **
  1202.  ***********************************************************************/
  1203. /*----------------------------------------------------------
  1204.  * String to point, point to string conversion.
  1205.  * External format:
  1206.  * "(x,y)"
  1207.  * "x,y"
  1208.  *---------------------------------------------------------*/
  1209. Point *
  1210. point_in(char *str)
  1211. {
  1212. Point    *point;
  1213. double x,
  1214. y;
  1215. char    *s;
  1216. if (!PointerIsValid(str))
  1217. elog(ERROR, "Bad (null) point external representation");
  1218. if (!pair_decode(str, &x, &y, &s) || (strlen(s) > 0))
  1219. elog(ERROR, "Bad point external representation '%s'", str);
  1220. point = palloc(sizeof(Point));
  1221. point->x = x;
  1222. point->y = y;
  1223. return point;
  1224. } /* point_in() */
  1225. char *
  1226. point_out(Point *pt)
  1227. {
  1228. if (!PointerIsValid(pt))
  1229. return NULL;
  1230. return path_encode(-1, 1, pt);
  1231. } /* point_out() */
  1232. static Point *
  1233. point_construct(double x, double y)
  1234. {
  1235. Point    *result = palloc(sizeof(Point));
  1236. result->x = x;
  1237. result->y = y;
  1238. return result;
  1239. }
  1240. static Point *
  1241. point_copy(Point *pt)
  1242. {
  1243. Point    *result;
  1244. if (!PointerIsValid(pt))
  1245. return NULL;
  1246. result = palloc(sizeof(Point));
  1247. result->x = pt->x;
  1248. result->y = pt->y;
  1249. return result;
  1250. }
  1251. /*----------------------------------------------------------
  1252.  * Relational operators for Points.
  1253.  * Since we do have a sense of coordinates being
  1254.  * "equal" to a given accuracy (point_vert, point_horiz),
  1255.  * the other ops must preserve that sense.  This means
  1256.  * that results may, strictly speaking, be a lie (unless
  1257.  * EPSILON = 0.0).
  1258.  *---------------------------------------------------------*/
  1259. bool
  1260. point_left(Point *pt1, Point *pt2)
  1261. {
  1262. return FPlt(pt1->x, pt2->x);
  1263. }
  1264. bool
  1265. point_right(Point *pt1, Point *pt2)
  1266. {
  1267. return FPgt(pt1->x, pt2->x);
  1268. }
  1269. bool
  1270. point_above(Point *pt1, Point *pt2)
  1271. {
  1272. return FPgt(pt1->y, pt2->y);
  1273. }
  1274. bool
  1275. point_below(Point *pt1, Point *pt2)
  1276. {
  1277. return FPlt(pt1->y, pt2->y);
  1278. }
  1279. bool
  1280. point_vert(Point *pt1, Point *pt2)
  1281. {
  1282. return FPeq(pt1->x, pt2->x);
  1283. }
  1284. bool
  1285. point_horiz(Point *pt1, Point *pt2)
  1286. {
  1287. return FPeq(pt1->y, pt2->y);
  1288. }
  1289. bool
  1290. point_eq(Point *pt1, Point *pt2)
  1291. {
  1292. return point_horiz(pt1, pt2) && point_vert(pt1, pt2);
  1293. }
  1294. bool
  1295. point_ne(Point *pt1, Point *pt2)
  1296. {
  1297. return !point_eq(pt1, pt2);
  1298. }
  1299. /*----------------------------------------------------------
  1300.  * "Arithmetic" operators on points.
  1301.  *---------------------------------------------------------*/
  1302. int32
  1303. pointdist(Point *p1, Point *p2)
  1304. {
  1305. int32 result;
  1306. result = point_dt(p1, p2);
  1307. return result;
  1308. }
  1309. double *
  1310. point_distance(Point *pt1, Point *pt2)
  1311. {
  1312. double    *result = palloc(sizeof(double));
  1313. *result = HYPOT(pt1->x - pt2->x, pt1->y - pt2->y);
  1314. return result;
  1315. }
  1316. double
  1317. point_dt(Point *pt1, Point *pt2)
  1318. {
  1319. #ifdef GEODEBUG
  1320. printf("point_dt- segment (%f,%f),(%f,%f) length is %fn",
  1321.    pt1->x, pt1->y, pt2->x, pt2->y, HYPOT(pt1->x - pt2->x, pt1->y - pt2->y));
  1322. #endif
  1323. return HYPOT(pt1->x - pt2->x, pt1->y - pt2->y);
  1324. }
  1325. double *
  1326. point_slope(Point *pt1, Point *pt2)
  1327. {
  1328. double    *result = palloc(sizeof(double));
  1329. if (point_vert(pt1, pt2))
  1330. *result = (double) DBL_MAX;
  1331. else
  1332. *result = (pt1->y - pt2->y) / (pt1->x - pt1->x);
  1333. return result;
  1334. }
  1335. double
  1336. point_sl(Point *pt1, Point *pt2)
  1337. {
  1338. return (point_vert(pt1, pt2)
  1339. ? (double) DBL_MAX
  1340. : (pt1->y - pt2->y) / (pt1->x - pt2->x));
  1341. }
  1342. /***********************************************************************
  1343.  **
  1344.  ** Routines for 2D line segments.
  1345.  **
  1346.  ***********************************************************************/
  1347. /*----------------------------------------------------------
  1348.  * String to lseg, lseg to string conversion.
  1349.  * External forms: "[(x1, y1), (x2, y2)]"
  1350.  * "(x1, y1), (x2, y2)"
  1351.  * "x1, y1, x2, y2"
  1352.  * closed form ok "((x1, y1), (x2, y2))"
  1353.  * (old form) "(x1, y1, x2, y2)"
  1354.  *---------------------------------------------------------*/
  1355. LSEG *
  1356. lseg_in(char *str)
  1357. {
  1358. LSEG    *lseg;
  1359. int isopen;
  1360. char    *s;
  1361. if (!PointerIsValid(str))
  1362. elog(ERROR, " Bad (null) lseg external representation", NULL);
  1363. lseg = palloc(sizeof(LSEG));
  1364. if ((!path_decode(TRUE, 2, str, &isopen, &s, &(lseg->p[0])))
  1365. || (*s != ''))
  1366. elog(ERROR, "Bad lseg external representation '%s'", str);
  1367. #ifdef NOT_USED
  1368. lseg->m = point_sl(&lseg->p[0], &lseg->p[1]);
  1369. #endif
  1370. return lseg;
  1371. } /* lseg_in() */
  1372. char *
  1373. lseg_out(LSEG *ls)
  1374. {
  1375. if (!PointerIsValid(ls))
  1376. return NULL;
  1377. return path_encode(FALSE, 2, (Point *) &(ls->p[0]));
  1378. } /* lseg_out() */
  1379. /* lseg_construct -
  1380.  * form a LSEG from two Points.
  1381.  */
  1382. LSEG *
  1383. lseg_construct(Point *pt1, Point *pt2)
  1384. {
  1385. LSEG    *result = palloc(sizeof(LSEG));
  1386. result->p[0].x = pt1->x;
  1387. result->p[0].y = pt1->y;
  1388. result->p[1].x = pt2->x;
  1389. result->p[1].y = pt2->y;
  1390. #ifdef NOT_USED
  1391. result->m = point_sl(pt1, pt2);
  1392. #endif
  1393. return result;
  1394. }
  1395. /* like lseg_construct, but assume space already allocated */
  1396. static void
  1397. statlseg_construct(LSEG *lseg, Point *pt1, Point *pt2)
  1398. {
  1399. lseg->p[0].x = pt1->x;
  1400. lseg->p[0].y = pt1->y;
  1401. lseg->p[1].x = pt2->x;
  1402. lseg->p[1].y = pt2->y;
  1403. #ifdef NOT_USED
  1404. lseg->m = point_sl(pt1, pt2);
  1405. #endif
  1406. }
  1407. double *
  1408. lseg_length(LSEG *lseg)
  1409. {
  1410. double    *result;
  1411. if (!PointerIsValid(lseg))
  1412. return NULL;
  1413. result = point_distance(&lseg->p[0], &lseg->p[1]);
  1414. return result;
  1415. } /* lseg_length() */
  1416. /*----------------------------------------------------------
  1417.  * Relative position routines.
  1418.  *---------------------------------------------------------*/
  1419. /*
  1420.  **  find intersection of the two lines, and see if it falls on
  1421.  **  both segments.
  1422.  */
  1423. bool
  1424. lseg_intersect(LSEG *l1, LSEG *l2)
  1425. {
  1426. LINE    *ln;
  1427. Point    *interpt;
  1428. bool retval;
  1429. ln = line_construct_pp(&l2->p[0], &l2->p[1]);
  1430. interpt = interpt_sl(l1, ln);
  1431. if (interpt != NULL && on_ps(interpt, l2)) /* interpt on l1 and l2 */
  1432. retval = TRUE;
  1433. else
  1434. retval = FALSE;
  1435. if (interpt != NULL)
  1436. pfree(interpt);
  1437. pfree(ln);
  1438. return retval;
  1439. }
  1440. bool
  1441. lseg_parallel(LSEG *l1, LSEG *l2)
  1442. {
  1443. #ifdef NOT_USED
  1444. return FPeq(l1->m, l2->m);
  1445. #endif
  1446. return (FPeq(point_sl(&(l1->p[0]), &(l1->p[1])),
  1447.  point_sl(&(l2->p[0]), &(l2->p[1]))));
  1448. } /* lseg_parallel() */
  1449. /* lseg_perp()
  1450.  * Determine if two line segments are perpendicular.
  1451.  *
  1452.  * This code did not get the correct answer for
  1453.  * '((0,0),(0,1))'::lseg ?-| '((0,0),(1,0))'::lseg
  1454.  * So, modified it to check explicitly for slope of vertical line
  1455.  * returned by point_sl() and the results seem better.
  1456.  * - thomas 1998-01-31
  1457.  */
  1458. bool
  1459. lseg_perp(LSEG *l1, LSEG *l2)
  1460. {
  1461. double m1,
  1462. m2;
  1463. m1 = point_sl(&(l1->p[0]), &(l1->p[1]));
  1464. m2 = point_sl(&(l2->p[0]), &(l2->p[1]));
  1465. #ifdef GEODEBUG
  1466. printf("lseg_perp- slopes are %g and %gn", m1, m2);
  1467. #endif
  1468. if (FPzero(m1))
  1469. return FPeq(m2, DBL_MAX);
  1470. else if (FPzero(m2))
  1471. return FPeq(m1, DBL_MAX);
  1472. return FPeq(m1 / m2, -1.0);
  1473. } /* lseg_perp() */
  1474. bool
  1475. lseg_vertical(LSEG *lseg)
  1476. {
  1477. return FPeq(lseg->p[0].x, lseg->p[1].x);
  1478. }
  1479. bool
  1480. lseg_horizontal(LSEG *lseg)
  1481. {
  1482. return FPeq(lseg->p[0].y, lseg->p[1].y);
  1483. }
  1484. bool
  1485. lseg_eq(LSEG *l1, LSEG *l2)
  1486. {
  1487. return (FPeq(l1->p[0].x, l2->p[0].x) &&
  1488. FPeq(l1->p[1].y, l2->p[1].y) &&
  1489. FPeq(l1->p[0].x, l2->p[0].x) &&
  1490. FPeq(l1->p[1].y, l2->p[1].y));
  1491. } /* lseg_eq() */
  1492. bool
  1493. lseg_ne(LSEG *l1, LSEG *l2)
  1494. {
  1495. return (!FPeq(l1->p[0].x, l2->p[0].x) ||
  1496. !FPeq(l1->p[1].y, l2->p[1].y) ||
  1497. !FPeq(l1->p[0].x, l2->p[0].x) ||
  1498. !FPeq(l1->p[1].y, l2->p[1].y));
  1499. } /* lseg_ne() */
  1500. bool
  1501. lseg_lt(LSEG *l1, LSEG *l2)
  1502. {
  1503. return FPlt(point_dt(&l1->p[0], &l1->p[1]), point_dt(&l2->p[0], &l2->p[1]));
  1504. } /* lseg_lt() */
  1505. bool
  1506. lseg_le(LSEG *l1, LSEG *l2)
  1507. {
  1508. return FPle(point_dt(&l1->p[0], &l1->p[1]), point_dt(&l2->p[0], &l2->p[1]));
  1509. } /* lseg_le() */
  1510. bool
  1511. lseg_gt(LSEG *l1, LSEG *l2)
  1512. {
  1513. return FPgt(point_dt(&l1->p[0], &l1->p[1]), point_dt(&l2->p[0], &l2->p[1]));
  1514. } /* lseg_gt() */
  1515. bool
  1516. lseg_ge(LSEG *l1, LSEG *l2)
  1517. {
  1518. return FPge(point_dt(&l1->p[0], &l1->p[1]), point_dt(&l2->p[0], &l2->p[1]));
  1519. } /* lseg_ge() */
  1520. /*----------------------------------------------------------
  1521.  * Line arithmetic routines.
  1522.  *---------------------------------------------------------*/
  1523. /* lseg_distance -
  1524.  * If two segments don't intersect, then the closest
  1525.  * point will be from one of the endpoints to the other
  1526.  * segment.
  1527.  */
  1528. double *
  1529. lseg_distance(LSEG *l1, LSEG *l2)
  1530. {
  1531. double    *result = palloc(sizeof(double));
  1532. *result = lseg_dt(l1, l2);
  1533. return result;
  1534. }
  1535. /* lseg_dt()
  1536.  * Distance between two line segments.
  1537.  * Must check both sets of endpoints to ensure minimum distance is found.
  1538.  * - thomas 1998-02-01
  1539.  */
  1540. static double
  1541. lseg_dt(LSEG *l1, LSEG *l2)
  1542. {
  1543. double    *d,
  1544. result;
  1545. if (lseg_intersect(l1, l2))
  1546. return 0.0;
  1547. d = dist_ps(&l1->p[0], l2);
  1548. result = *d;
  1549. pfree(d);
  1550. d = dist_ps(&l1->p[1], l2);
  1551. result = Min(result, *d);
  1552. pfree(d);
  1553. d = dist_ps(&l2->p[0], l1);
  1554. result = Min(result, *d);
  1555. pfree(d);
  1556. d = dist_ps(&l2->p[1], l1);
  1557. result = Min(result, *d);
  1558. pfree(d);
  1559. return result;
  1560. } /* lseg_dt() */
  1561. Point *
  1562. lseg_center(LSEG *lseg)
  1563. {
  1564. Point    *result;
  1565. if (!PointerIsValid(lseg))
  1566. return NULL;
  1567. result = palloc(sizeof(Point));
  1568. result->x = (lseg->p[0].x - lseg->p[1].x) / 2;
  1569. result->y = (lseg->p[0].y - lseg->p[1].y) / 2;
  1570. return result;
  1571. } /* lseg_center() */
  1572. /* lseg_interpt -
  1573.  * Find the intersection point of two segments (if any).
  1574.  * Find the intersection of the appropriate lines; if the
  1575.  * point is not on a given segment, there is no valid segment
  1576.  * intersection point at all.
  1577.  * If there is an intersection, then check explicitly for matching
  1578.  * endpoints since there may be rounding effects with annoying
  1579.  * lsb residue. - tgl 1997-07-09
  1580.  */
  1581. Point *
  1582. lseg_interpt(LSEG *l1, LSEG *l2)
  1583. {
  1584. Point    *result;
  1585. LINE    *tmp1,
  1586.    *tmp2;
  1587. if (!PointerIsValid(l1) || !PointerIsValid(l2))
  1588. return NULL;
  1589. tmp1 = line_construct_pp(&l1->p[0], &l1->p[1]);
  1590. tmp2 = line_construct_pp(&l2->p[0], &l2->p[1]);
  1591. result = line_interpt(tmp1, tmp2);
  1592. if (PointerIsValid(result))
  1593. {
  1594. if (on_ps(result, l1))
  1595. {
  1596. if ((FPeq(l1->p[0].x, l2->p[0].x) && FPeq(l1->p[0].y, l2->p[0].y))
  1597. || (FPeq(l1->p[0].x, l2->p[1].x) && FPeq(l1->p[0].y, l2->p[1].y)))
  1598. {
  1599. result->x = l1->p[0].x;
  1600. result->y = l1->p[0].y;
  1601. }
  1602. else if ((FPeq(l1->p[1].x, l2->p[0].x) && FPeq(l1->p[1].y, l2->p[0].y))
  1603.  || (FPeq(l1->p[1].x, l2->p[1].x) && FPeq(l1->p[1].y, l2->p[1].y)))
  1604. {
  1605. result->x = l1->p[1].x;
  1606. result->y = l1->p[1].y;
  1607. }
  1608. }
  1609. else
  1610. {
  1611. pfree(result);
  1612. result = NULL;
  1613. }
  1614. }
  1615. pfree(tmp1);
  1616. pfree(tmp2);
  1617. return result;
  1618. } /* lseg_interpt() */
  1619. /***********************************************************************
  1620.  **
  1621.  ** Routines for position comparisons of differently-typed
  1622.  ** 2D objects.
  1623.  **
  1624.  ***********************************************************************/
  1625. #define ABOVE 1
  1626. #define BELOW 0
  1627. #define UNDEF -1
  1628. /*---------------------------------------------------------------------
  1629.  * dist_
  1630.  * Minimum distance from one object to another.
  1631.  *-------------------------------------------------------------------*/
  1632. double *
  1633. dist_pl(Point *pt, LINE *line)
  1634. {
  1635. double    *result = palloc(sizeof(double));
  1636. *result = (line->A * pt->x + line->B * pt->y + line->C) /
  1637. HYPOT(line->A, line->B);
  1638. return result;
  1639. }
  1640. double *
  1641. dist_ps(Point *pt, LSEG *lseg)
  1642. {
  1643. double m; /* slope of perp. */
  1644. LINE    *ln;
  1645. double    *result,
  1646.    *tmpdist;
  1647. Point    *ip;
  1648. /*
  1649.  * Construct a line perpendicular to the input segment
  1650.  * and through the input point
  1651.  */
  1652. if (lseg->p[1].x == lseg->p[0].x)
  1653. m = 0;
  1654. else if (lseg->p[1].y == lseg->p[0].y)
  1655. { /* slope is infinite */
  1656. m = (double) DBL_MAX;
  1657. }
  1658. else
  1659. {
  1660. #ifdef NOT_USED
  1661. m = (-1) * (lseg->p[1].y - lseg->p[0].y) /
  1662. (lseg->p[1].x - lseg->p[0].x);
  1663. #endif
  1664. m = ((lseg->p[0].y - lseg->p[1].y) / (lseg->p[1].x - lseg->p[0].x));
  1665. }
  1666. ln = line_construct_pm(pt, m);
  1667. #ifdef GEODEBUG
  1668. printf("dist_ps- line is A=%g B=%g C=%g from (point) slope (%f,%f) %gn",
  1669.    ln->A, ln->B, ln->C, pt->x, pt->y, m);
  1670. #endif
  1671. /*
  1672.  * Calculate distance to the line segment
  1673.  * or to the endpoints of the segment.
  1674.  */
  1675. /* intersection is on the line segment? */
  1676. if ((ip = interpt_sl(lseg, ln)) != NULL)
  1677. {
  1678. result = point_distance(pt, ip);
  1679. #ifdef GEODEBUG
  1680. printf("dist_ps- distance is %f to intersection point is (%f,%f)n",
  1681.    *result, ip->x, ip->y);
  1682. #endif
  1683. /* otherwise, intersection is not on line segment */
  1684. }
  1685. else
  1686. {
  1687. result = point_distance(pt, &lseg->p[0]);
  1688. tmpdist = point_distance(pt, &lseg->p[1]);
  1689. if (*tmpdist < *result)
  1690. *result = *tmpdist;
  1691. pfree(tmpdist);
  1692. }
  1693. if (ip != NULL)
  1694. pfree(ip);
  1695. pfree(ln);
  1696. return result;
  1697. }
  1698. /*
  1699.  ** Distance from a point to a path
  1700.  */
  1701. double *
  1702. dist_ppath(Point *pt, PATH *path)
  1703. {
  1704. double    *result;
  1705. double    *tmp;
  1706. int i;
  1707. LSEG lseg;
  1708. switch (path->npts)
  1709. {
  1710. /* no points in path? then result is undefined... */
  1711. case 0:
  1712. result = NULL;
  1713. break;
  1714. /* one point in path? then get distance between two points... */
  1715. case 1:
  1716. result = point_distance(pt, &path->p[0]);
  1717. break;
  1718. default:
  1719. /* make sure the path makes sense... */
  1720. Assert(path->npts > 1);
  1721. /*
  1722.  * the distance from a point to a path is the smallest
  1723.  * distance from the point to any of its constituent segments.
  1724.  */
  1725. result = palloc(sizeof(double));
  1726. for (i = 0; i < path->npts - 1; i++)
  1727. {
  1728. statlseg_construct(&lseg, &path->p[i], &path->p[i + 1]);
  1729. tmp = dist_ps(pt, &lseg);
  1730. if (i == 0 || *tmp < *result)
  1731. *result = *tmp;
  1732. pfree(tmp);
  1733. }
  1734. break;
  1735. }
  1736. return result;
  1737. }
  1738. double *
  1739. dist_pb(Point *pt, BOX *box)
  1740. {
  1741. Point    *tmp;
  1742. double    *result;
  1743. tmp = close_pb(pt, box);
  1744. result = point_distance(tmp, pt);
  1745. pfree(tmp);
  1746. return result;
  1747. }
  1748. double *
  1749. dist_sl(LSEG *lseg, LINE *line)
  1750. {
  1751. double    *result,
  1752.    *d2;
  1753. if (inter_sl(lseg, line))
  1754. {
  1755. result = palloc(sizeof(double));
  1756. *result = 0.0;
  1757. }
  1758. else
  1759. {
  1760. result = dist_pl(&lseg->p[0], line);
  1761. d2 = dist_pl(&lseg->p[1], line);
  1762. if (*d2 > *result)
  1763. {
  1764. pfree(result);
  1765. result = d2;
  1766. }
  1767. else
  1768. pfree(d2);
  1769. }
  1770. return result;
  1771. }
  1772. double *
  1773. dist_sb(LSEG *lseg, BOX *box)
  1774. {
  1775. Point    *tmp;
  1776. double    *result;
  1777. tmp = close_sb(lseg, box);
  1778. if (tmp == NULL)
  1779. {
  1780. result = palloc(sizeof(double));
  1781. *result = 0.0;
  1782. }
  1783. else
  1784. {
  1785. result = dist_pb(tmp, box);
  1786. pfree(tmp);
  1787. }
  1788. return result;
  1789. }
  1790. double *
  1791. dist_lb(LINE *line, BOX *box)
  1792. {
  1793. Point    *tmp;
  1794. double    *result;
  1795. tmp = close_lb(line, box);
  1796. if (tmp == NULL)
  1797. {
  1798. result = palloc(sizeof(double));
  1799. *result = 0.0;
  1800. }
  1801. else
  1802. {
  1803. result = dist_pb(tmp, box);
  1804. pfree(tmp);
  1805. }
  1806. return result;
  1807. }
  1808. double *
  1809. dist_cpoly(CIRCLE *circle, POLYGON *poly)
  1810. {
  1811. double    *result;
  1812. int i;
  1813. double    *d;
  1814. LSEG seg;
  1815. if (!PointerIsValid(circle) || !PointerIsValid(poly))
  1816. elog(ERROR, "Invalid (null) input for distance", NULL);
  1817. if (point_inside(&(circle->center), poly->npts, poly->p))
  1818. {
  1819. #ifdef GEODEBUG
  1820. printf("dist_cpoly- center inside of polygonn");
  1821. #endif
  1822. result = palloc(sizeof(double));
  1823. *result = 0;
  1824. return result;
  1825. }
  1826. /* initialize distance with segment between first and last points */
  1827. seg.p[0].x = poly->p[0].x;
  1828. seg.p[0].y = poly->p[0].y;
  1829. seg.p[1].x = poly->p[poly->npts - 1].x;
  1830. seg.p[1].y = poly->p[poly->npts - 1].y;
  1831. result = dist_ps(&(circle->center), &seg);
  1832. #ifdef GEODEBUG
  1833. printf("dist_cpoly- segment 0/n distance is %fn", *result);
  1834. #endif
  1835. /* check distances for other segments */
  1836. for (i = 0; (i < poly->npts - 1); i++)
  1837. {
  1838. seg.p[0].x = poly->p[i].x;
  1839. seg.p[0].y = poly->p[i].y;
  1840. seg.p[1].x = poly->p[i + 1].x;
  1841. seg.p[1].y = poly->p[i + 1].y;
  1842. d = dist_ps(&(circle->center), &seg);
  1843. #ifdef GEODEBUG
  1844. printf("dist_cpoly- segment %d distance is %fn", (i + 1), *d);
  1845. #endif
  1846. if (*d < *result)
  1847. *result = *d;
  1848. pfree(d);
  1849. }
  1850. *result -= circle->radius;
  1851. if (*result < 0)
  1852. *result = 0;
  1853. return result;
  1854. } /* dist_cpoly() */
  1855. /*---------------------------------------------------------------------
  1856.  * interpt_
  1857.  * Intersection point of objects.
  1858.  * We choose to ignore the "point" of intersection between
  1859.  *   lines and boxes, since there are typically two.
  1860.  *-------------------------------------------------------------------*/
  1861. static Point *
  1862. interpt_sl(LSEG *lseg, LINE *line)
  1863. {
  1864. LINE    *tmp;
  1865. Point    *p;
  1866. tmp = line_construct_pp(&lseg->p[0], &lseg->p[1]);
  1867. p = line_interpt(tmp, line);
  1868. #ifdef GEODEBUG
  1869. printf("interpt_sl- segment is (%.*g %.*g) (%.*g %.*g)n",
  1870.    digits8, lseg->p[0].x, digits8, lseg->p[0].y, digits8, lseg->p[1].x, digits8, lseg->p[1].y);
  1871. printf("interpt_sl- segment becomes line A=%.*g B=%.*g C=%.*gn",
  1872.    digits8, tmp->A, digits8, tmp->B, digits8, tmp->C);
  1873. #endif
  1874. if (PointerIsValid(p))
  1875. {
  1876. #ifdef GEODEBUG
  1877. printf("interpt_sl- intersection point is (%.*g %.*g)n", digits8, p->x, digits8, p->y);
  1878. #endif
  1879. if (on_ps(p, lseg))
  1880. {
  1881. #ifdef GEODEBUG
  1882. printf("interpt_sl- intersection point is on segmentn");
  1883. #endif
  1884. }
  1885. else
  1886. {
  1887. pfree(p);
  1888. p = NULL;
  1889. }
  1890. }
  1891. pfree(tmp);
  1892. return p;
  1893. }
  1894. /*---------------------------------------------------------------------
  1895.  * close_
  1896.  * Point of closest proximity between objects.
  1897.  *-------------------------------------------------------------------*/
  1898. /* close_pl -
  1899.  * The intersection point of a perpendicular of the line
  1900.  * through the point.
  1901.  */
  1902. Point *
  1903. close_pl(Point *pt, LINE *line)
  1904. {
  1905. Point    *result;
  1906. LINE    *tmp;
  1907. double invm;
  1908. result = palloc(sizeof(Point));
  1909. #ifdef NOT_USED
  1910. if (FPeq(line->A, -1.0) && FPzero(line->B))
  1911. { /* vertical */
  1912. }
  1913. #endif
  1914. if (line_vertical(line))
  1915. {
  1916. result->x = line->C;
  1917. result->y = pt->y;
  1918. return result;
  1919. #ifdef NOT_USED
  1920. }
  1921. else if (FPzero(line->m))
  1922. { /* horizontal */
  1923. #endif
  1924. }
  1925. else if (line_horizontal(line))
  1926. {
  1927. result->x = pt->x;
  1928. result->y = line->C;
  1929. return result;
  1930. }
  1931. /* drop a perpendicular and find the intersection point */
  1932. #ifdef NOT_USED
  1933. invm = -1.0 / line->m;
  1934. #endif
  1935. /* invert and flip the sign on the slope to get a perpendicular */
  1936. invm = line->B / line->A;
  1937. tmp = line_construct_pm(pt, invm);
  1938. result = line_interpt(tmp, line);
  1939. return result;
  1940. } /* close_pl() */
  1941. /* close_ps()
  1942.  * Closest point on line segment to specified point.
  1943.  * Take the closest endpoint if the point is left, right,
  1944.  * above, or below the segment, otherwise find the intersection
  1945.  * point of the segment and its perpendicular through the point.
  1946.  *
  1947.  * Some tricky code here, relying on boolean expressions
  1948.  * evaluating to only zero or one to use as an array index.
  1949.  * bug fixes by gthaker@atl.lmco.com; May 1, 1998
  1950.  */
  1951. Point *
  1952. close_ps(Point *pt, LSEG *lseg)
  1953. {
  1954. Point    *result;
  1955. LINE    *tmp;
  1956. double invm;
  1957. int xh,
  1958. yh;
  1959. #ifdef GEODEBUG
  1960. printf("close_sp:pt->x %f pt->y %fnlseg(0).x %f lseg(0).y %f  lseg(1).x %f lseg(1).y %fn",
  1961. pt->x, pt->y, lseg->p[0].x, lseg->p[0].y, lseg->p[1].x, lseg->p[1].y);
  1962. #endif
  1963. result = NULL;
  1964. xh = lseg->p[0].x < lseg->p[1].x;
  1965. yh = lseg->p[0].y < lseg->p[1].y;
  1966. /* !xh (or !yh) is the index of lower x( or y) end point of lseg */
  1967. /* vertical segment? */
  1968. if (lseg_vertical(lseg))
  1969. {
  1970. #ifdef GEODEBUG
  1971. printf("close_ps- segment is verticaln");
  1972. #endif
  1973. /* first check if point is below or above the entire lseg. */
  1974. if (pt->y < lseg->p[!yh].y)
  1975. result = point_copy(&lseg->p[!yh]); /* below the lseg */
  1976. else if (pt->y > lseg->p[yh].y)
  1977. result = point_copy(&lseg->p[yh]); /* above the lseg */
  1978. if (result != NULL)
  1979. return result;
  1980. /* point lines along (to left or right) of the vertical lseg. */
  1981. result = palloc(sizeof(*result));
  1982. result->x = lseg->p[0].x;
  1983. result->y = pt->y;
  1984. return result;
  1985. }
  1986. else if (lseg_horizontal(lseg))
  1987. {
  1988. #ifdef GEODEBUG
  1989. printf("close_ps- segment is horizontaln");
  1990. #endif
  1991. /* first check if point is left or right of the entire lseg. */
  1992. if (pt->x < lseg->p[!xh].x)
  1993. result = point_copy(&lseg->p[!xh]); /* left of the lseg */
  1994. else if (pt->x > lseg->p[xh].x)
  1995. result = point_copy(&lseg->p[xh]); /* right of the lseg */
  1996. if (result != NULL)
  1997. return result;
  1998. /* point lines along (at top or below) the horiz. lseg. */
  1999. result = palloc(sizeof(*result));
  2000. result->x = pt->x;
  2001. result->y = lseg->p[0].y;
  2002. return result;
  2003. }
  2004. /*
  2005.  * vert. and horiz. cases are down, now check if the closest point is
  2006.  * one of the end points or someplace on the lseg.
  2007.  */
  2008. /* TODO: Ask if "tmp" should be freed to prevent memory leak */
  2009. invm = -1.0 / point_sl(&(lseg->p[0]), &(lseg->p[1]));
  2010. tmp = line_construct_pm(&lseg->p[!yh], invm); /* lower edge of the
  2011.  * "band" */
  2012. if (pt->y < (tmp->A * pt->x + tmp->C))
  2013. { /* we are below the lower edge */
  2014. result = point_copy(&lseg->p[!yh]); /* below the lseg, take
  2015.  * lower end pt */
  2016. /*   fprintf(stderr,"below: tmp A %f  B %f   C %f    m %fn",tmp->A,tmp->B,tmp->C, tmp->m); */
  2017. return result;
  2018. }
  2019. tmp = line_construct_pm(&lseg->p[yh], invm); /* upper edge of the
  2020.  * "band" */
  2021. if (pt->y > (tmp->A * pt->x + tmp->C))
  2022. { /* we are below the lower edge */
  2023. result = point_copy(&lseg->p[yh]); /* above the lseg, take
  2024.  * higher end pt */
  2025. /*   fprintf(stderr,"above: tmp A %f  B %f   C %f    m %fn",tmp->A,tmp->B,tmp->C, tmp->m); */
  2026. return result;
  2027. }
  2028. /*
  2029.  * at this point the "normal" from point will hit lseg. The closet
  2030.  * point will be somewhere on the lseg
  2031.  */
  2032. tmp = line_construct_pm(pt, invm);
  2033. /* fprintf(stderr,"tmp A %f  B %f   C %f    m %fn",tmp->A,tmp->B,tmp->C, tmp->m); */
  2034. result = interpt_sl(lseg, tmp);
  2035. /* fprintf(stderr,"result.x %f  result.y %fn", result->x, result->y); */
  2036. return result;
  2037. } /* close_ps() */
  2038. /* close_lseg()
  2039.  * Closest point to l1 on l2.
  2040.  */
  2041. Point *
  2042. close_lseg(LSEG *l1, LSEG *l2)
  2043. {
  2044. Point    *result = NULL;
  2045. Point point;
  2046. double dist;
  2047. double    *d;
  2048. d = dist_ps(&l1->p[0], l2);
  2049. dist = *d;
  2050. memcpy(&point, &l1->p[0], sizeof(point));
  2051. pfree(d);
  2052. if (*(d = dist_ps(&l1->p[1], l2)) < dist)
  2053. {
  2054. dist = *d;
  2055. memcpy(&point, &l1->p[1], sizeof(point));
  2056. }
  2057. pfree(d);
  2058. if (*(d = dist_ps(&l2->p[0], l1)) < dist)
  2059. {
  2060. result = close_ps(&l2->p[0], l1);
  2061. memcpy(&point, result, sizeof(point));
  2062. pfree(result);
  2063. result = close_ps(&point, l2);
  2064. }
  2065. pfree(d);
  2066. if (*(d = dist_ps(&l2->p[1], l1)) < dist)
  2067. {
  2068. if (result != NULL)
  2069. pfree(result);
  2070. result = close_ps(&l2->p[1], l1);
  2071. memcpy(&point, result, sizeof(point));
  2072. pfree(result);
  2073. result = close_ps(&point, l2);
  2074. }
  2075. pfree(d);
  2076. if (result == NULL)
  2077. {
  2078. result = palloc(sizeof(*result));
  2079. memcpy(result, &point, sizeof(*result));
  2080. }
  2081. return result;
  2082. } /* close_lseg() */
  2083. /* close_pb()
  2084.  * Closest point on or in box to specified point.
  2085.  */
  2086. Point *
  2087. close_pb(Point *pt, BOX *box)
  2088. {
  2089. LSEG lseg,
  2090. seg;
  2091. Point point;
  2092. double dist,
  2093.    *d;
  2094. if (on_pb(pt, box))
  2095. return pt;
  2096. /* pairwise check lseg distances */
  2097. point.x = box->low.x;
  2098. point.y = box->high.y;
  2099. statlseg_construct(&lseg, &box->low, &point);
  2100. dist = *(d = dist_ps(pt, &lseg));
  2101. pfree(d);
  2102. statlseg_construct(&seg, &box->high, &point);
  2103. if (*(d = dist_ps(pt, &seg)) < dist)
  2104. {
  2105. dist = *d;
  2106. memcpy(&lseg, &seg, sizeof(lseg));
  2107. }
  2108. pfree(d);
  2109. point.x = box->high.x;
  2110. point.y = box->low.y;
  2111. statlseg_construct(&seg, &box->low, &point);
  2112. if (*(d = dist_ps(pt, &seg)) < dist)
  2113. {
  2114. dist = *d;
  2115. memcpy(&lseg, &seg, sizeof(lseg));
  2116. }
  2117. pfree(d);
  2118. statlseg_construct(&seg, &box->high, &point);
  2119. if (*(d = dist_ps(pt, &seg)) < dist)
  2120. {
  2121. dist = *d;
  2122. memcpy(&lseg, &seg, sizeof(lseg));
  2123. }
  2124. pfree(d);
  2125. return close_ps(pt, &lseg);
  2126. } /* close_pb() */
  2127. /* close_sl()
  2128.  * Closest point on line to line segment.
  2129.  *
  2130.  * XXX THIS CODE IS WRONG
  2131.  * The code is actually calculating the point on the line segment
  2132.  * which is backwards from the routine naming convention.
  2133.  * Copied code to new routine close_ls() but haven't fixed this one yet.
  2134.  * - thomas 1998-01-31
  2135.  */
  2136. Point *
  2137. close_sl(LSEG *lseg, LINE *line)
  2138. {
  2139. Point    *result;
  2140. double    *d1,
  2141.    *d2;
  2142. result = interpt_sl(lseg, line);
  2143. if (result)
  2144. return result;
  2145. d1 = dist_pl(&lseg->p[0], line);
  2146. d2 = dist_pl(&lseg->p[1], line);
  2147. if (d1 < d2)
  2148. result = point_copy(&lseg->p[0]);
  2149. else
  2150. result = point_copy(&lseg->p[1]);
  2151. pfree(d1);
  2152. pfree(d2);
  2153. return result;
  2154. }
  2155. /* close_ls()
  2156.  * Closest point on line segment to line.
  2157.  */
  2158. Point *
  2159. close_ls(LINE *line, LSEG *lseg)
  2160. {
  2161. Point    *result;
  2162. double    *d1,
  2163.    *d2;
  2164. result = interpt_sl(lseg, line);
  2165. if (result)
  2166. return result;
  2167. d1 = dist_pl(&lseg->p[0], line);
  2168. d2 = dist_pl(&lseg->p[1], line);
  2169. if (d1 < d2)
  2170. result = point_copy(&lseg->p[0]);
  2171. else
  2172. result = point_copy(&lseg->p[1]);
  2173. pfree(d1);
  2174. pfree(d2);
  2175. return result;
  2176. } /* close_ls() */
  2177. /* close_sb()
  2178.  * Closest point on or in box to line segment.
  2179.  */
  2180. Point *
  2181. close_sb(LSEG *lseg, BOX *box)
  2182. {
  2183. Point    *result;
  2184. Point    *pt;
  2185. Point point;
  2186. LSEG bseg,
  2187. seg;
  2188. double dist,
  2189. d;
  2190. /* segment intersects box? then just return closest point to center */
  2191. if (inter_sb(lseg, box))
  2192. {
  2193. pt = box_center(box);
  2194. result = close_ps(pt, lseg);
  2195. pfree(pt);
  2196. return result;
  2197. }
  2198. /* pairwise check lseg distances */
  2199. point.x = box->low.x;
  2200. point.y = box->high.y;
  2201. statlseg_construct(&bseg, &box->low, &point);
  2202. dist = lseg_dt(lseg, &bseg);
  2203. statlseg_construct(&seg, &box->high, &point);
  2204. if ((d = lseg_dt(lseg, &seg)) < dist)
  2205. {
  2206. dist = d;
  2207. memcpy(&bseg, &seg, sizeof(bseg));
  2208. }
  2209. point.x = box->high.x;
  2210. point.y = box->low.y;
  2211. statlseg_construct(&seg, &box->low, &point);
  2212. if ((d = lseg_dt(lseg, &seg)) < dist)
  2213. {
  2214. dist = d;
  2215. memcpy(&bseg, &seg, sizeof(bseg));
  2216. }
  2217. statlseg_construct(&seg, &box->high, &point);
  2218. if ((d = lseg_dt(lseg, &seg)) < dist)
  2219. {
  2220. dist = d;
  2221. memcpy(&bseg, &seg, sizeof(bseg));
  2222. }
  2223. /* OK, we now have the closest line segment on the box boundary */
  2224. return close_lseg(lseg, &bseg);
  2225. } /* close_sb() */
  2226. Point *
  2227. close_lb(LINE *line, BOX *box)
  2228. {
  2229. /* think about this one for a while */
  2230. elog(ERROR, "close_lb not implemented", NULL);
  2231. return NULL;
  2232. }
  2233. /*---------------------------------------------------------------------
  2234.  * on_
  2235.  * Whether one object lies completely within another.
  2236.  *-------------------------------------------------------------------*/
  2237. /* on_pl -
  2238.  * Does the point satisfy the equation?
  2239.  */
  2240. bool
  2241. on_pl(Point *pt, LINE *line)
  2242. {
  2243. if (!PointerIsValid(pt) || !PointerIsValid(line))
  2244. return FALSE;
  2245. return FPzero(line->A * pt->x + line->B * pt->y + line->C);
  2246. }
  2247. /* on_ps -
  2248.  * Determine colinearity by detecting a triangle inequality.
  2249.  * This algorithm seems to behave nicely even with lsb residues - tgl 1997-07-09
  2250.  */
  2251. bool
  2252. on_ps(Point *pt, LSEG *lseg)
  2253. {
  2254. if (!PointerIsValid(pt) || !PointerIsValid(lseg))
  2255. return FALSE;
  2256. return (FPeq(point_dt(pt, &lseg->p[0]) + point_dt(pt, &lseg->p[1]),
  2257.  point_dt(&lseg->p[0], &lseg->p[1])));
  2258. }
  2259. bool
  2260. on_pb(Point *pt, BOX *box)
  2261. {
  2262. if (!PointerIsValid(pt) || !PointerIsValid(box))
  2263. return FALSE;
  2264. return (pt->x <= box->high.x && pt->x >= box->low.x &&
  2265. pt->y <= box->high.y && pt->y >= box->low.y);
  2266. }
  2267. /* on_ppath -
  2268.  * Whether a point lies within (on) a polyline.
  2269.  * If open, we have to (groan) check each segment.
  2270.  * (uses same algorithm as for point intersecting segment - tgl 1997-07-09)
  2271.  * If closed, we use the old O(n) ray method for point-in-polygon.
  2272.  * The ray is horizontal, from pt out to the right.
  2273.  * Each segment that crosses the ray counts as an
  2274.  * intersection; note that an endpoint or edge may touch
  2275.  * but not cross.
  2276.  * (we can do p-in-p in lg(n), but it takes preprocessing)
  2277.  */
  2278. #define NEXT(A) ((A+1) % path->npts) /* cyclic "i+1" */
  2279. bool
  2280. on_ppath(Point *pt, PATH *path)
  2281. {
  2282. int i,
  2283. n;
  2284. double a,
  2285. b;
  2286. if (!PointerIsValid(pt) || !PointerIsValid(path))
  2287. return FALSE;
  2288. /*-- OPEN --*/
  2289. if (!path->closed)
  2290. {
  2291. n = path->npts - 1;
  2292. a = point_dt(pt, &path->p[0]);
  2293. for (i = 0; i < n; i++)
  2294. {
  2295. b = point_dt(pt, &path->p[i + 1]);
  2296. if (FPeq(a + b,
  2297.  point_dt(&path->p[i], &path->p[i + 1])))
  2298. return TRUE;
  2299. a = b;
  2300. }
  2301. return FALSE;
  2302. }
  2303. /*-- CLOSED --*/
  2304. return point_inside(pt, path->npts, path->p);
  2305. } /* on_ppath() */
  2306. bool
  2307. on_sl(LSEG *lseg, LINE *line)
  2308. {
  2309. if (!PointerIsValid(lseg) || !PointerIsValid(line))
  2310. return FALSE;
  2311. return on_pl(&lseg->p[0], line) && on_pl(&lseg->p[1], line);
  2312. } /* on_sl() */
  2313. bool
  2314. on_sb(LSEG *lseg, BOX *box)
  2315. {
  2316. if (!PointerIsValid(lseg) || !PointerIsValid(box))
  2317. return FALSE;
  2318. return on_pb(&lseg->p[0], box) && on_pb(&lseg->p[1], box);
  2319. } /* on_sb() */
  2320. /*---------------------------------------------------------------------
  2321.  * inter_
  2322.  * Whether one object intersects another.
  2323.  *-------------------------------------------------------------------*/
  2324. bool
  2325. inter_sl(LSEG *lseg, LINE *line)
  2326. {
  2327. Point    *tmp;
  2328. if (!PointerIsValid(lseg) || !PointerIsValid(line))
  2329. return FALSE;
  2330. tmp = interpt_sl(lseg, line);
  2331. if (tmp)
  2332. {
  2333. pfree(tmp);
  2334. return TRUE;
  2335. }
  2336. return FALSE;
  2337. }
  2338. /* inter_sb()
  2339.  * Do line segment and box intersect?
  2340.  *
  2341.  * Segment completely inside box counts as intersection.
  2342.  * If you want only segments crossing box boundaries,
  2343.  * try converting box to path first.
  2344.  *
  2345.  * Optimize for non-intersection by checking for box intersection first.
  2346.  * - thomas 1998-01-30
  2347.  */
  2348. bool
  2349. inter_sb(LSEG *lseg, BOX *box)
  2350. {
  2351. BOX lbox;
  2352. LSEG bseg;
  2353. Point point;
  2354. if (!PointerIsValid(lseg) || !PointerIsValid(box))
  2355. return FALSE;
  2356. lbox.low.x = Min(lseg->p[0].x, lseg->p[1].x);
  2357. lbox.low.y = Min(lseg->p[0].y, lseg->p[1].y);
  2358. lbox.high.x = Max(lseg->p[0].x, lseg->p[1].x);
  2359. lbox.high.y = Max(lseg->p[0].y, lseg->p[1].y);
  2360. /* nothing close to overlap? then not going to intersect */
  2361. if (!box_overlap(&lbox, box))
  2362. return FALSE;
  2363. /* an endpoint of segment is inside box? then clearly intersects */
  2364. if (on_pb(&lseg->p[0], box) || on_pb(&lseg->p[1], box))
  2365. return TRUE;
  2366. /* pairwise check lseg intersections */
  2367. point.x = box->low.x;
  2368. point.y = box->high.y;
  2369. statlseg_construct(&bseg, &box->low, &point);
  2370. if (lseg_intersect(&bseg, lseg))
  2371. return TRUE;
  2372. statlseg_construct(&bseg, &box->high, &point);
  2373. if (lseg_intersect(&bseg, lseg))
  2374. return TRUE;
  2375. point.x = box->high.x;
  2376. point.y = box->low.y;
  2377. statlseg_construct(&bseg, &box->low, &point);
  2378. if (lseg_intersect(&bseg, lseg))
  2379. return TRUE;
  2380. statlseg_construct(&bseg, &box->high, &point);
  2381. if (lseg_intersect(&bseg, lseg))
  2382. return TRUE;
  2383. /* if we dropped through, no two segs intersected */
  2384. return FALSE;
  2385. } /* inter_sb() */
  2386. /* inter_lb()
  2387.  * Do line and box intersect?
  2388.  */
  2389. bool
  2390. inter_lb(LINE *line, BOX *box)
  2391. {
  2392. LSEG bseg;
  2393. Point p1,
  2394. p2;
  2395. if (!PointerIsValid(line) || !PointerIsValid(box))
  2396. return FALSE;
  2397. /* pairwise check lseg intersections */
  2398. p1.x = box->low.x;
  2399. p1.y = box->low.y;
  2400. p2.x = box->low.x;
  2401. p2.y = box->high.y;
  2402. statlseg_construct(&bseg, &p1, &p2);
  2403. if (inter_sl(&bseg, line))
  2404. return TRUE;
  2405. p1.x = box->high.x;
  2406. p1.y = box->high.y;
  2407. statlseg_construct(&bseg, &p1, &p2);
  2408. if (inter_sl(&bseg, line))
  2409. return TRUE;
  2410. p2.x = box->high.x;
  2411. p2.y = box->low.y;
  2412. statlseg_construct(&bseg, &p1, &p2);
  2413. if (inter_sl(&bseg, line))
  2414. return TRUE;
  2415. p1.x = box->low.x;
  2416. p1.y = box->low.y;
  2417. statlseg_construct(&bseg, &p1, &p2);
  2418. if (inter_sl(&bseg, line))
  2419. return TRUE;
  2420. /* if we dropped through, no intersection */
  2421. return FALSE;
  2422. }
  2423. /*------------------------------------------------------------------
  2424.  * The following routines define a data type and operator class for
  2425.  * POLYGONS .... Part of which (the polygon's bounding box) is built on
  2426.  * top of the BOX data type.
  2427.  *
  2428.  * make_bound_box - create the bounding box for the input polygon
  2429.  *------------------------------------------------------------------*/
  2430. /*---------------------------------------------------------------------
  2431.  * Make the smallest bounding box for the given polygon.
  2432.  *---------------------------------------------------------------------*/
  2433. static void
  2434. make_bound_box(POLYGON *poly)
  2435. {
  2436. int i;
  2437. double x1,
  2438. y1,
  2439. x2,
  2440. y2;
  2441. if (poly->npts > 0)
  2442. {
  2443. x2 = x1 = poly->p[0].x;
  2444. y2 = y1 = poly->p[0].y;
  2445. for (i = 1; i < poly->npts; i++)
  2446. {
  2447. if (poly->p[i].x < x1)
  2448. x1 = poly->p[i].x;
  2449. if (poly->p[i].x > x2)
  2450. x2 = poly->p[i].x;
  2451. if (poly->p[i].y < y1)
  2452. y1 = poly->p[i].y;
  2453. if (poly->p[i].y > y2)
  2454. y2 = poly->p[i].y;
  2455. }
  2456. box_fill(&(poly->boundbox), x1, x2, y1, y2);
  2457. }
  2458. else
  2459. elog(ERROR, "Unable to create bounding box for empty polygon", NULL);
  2460. }
  2461. /*------------------------------------------------------------------
  2462.  * poly_in - read in the polygon from a string specification
  2463.  *
  2464.  * External format:
  2465.  * "((x0,y0),...,(xn,yn))"
  2466.  * "x0,y0,...,xn,yn"
  2467.  * also supports the older style "(x1,...,xn,y1,...yn)"
  2468.  *------------------------------------------------------------------*/
  2469. POLYGON    *
  2470. poly_in(char *str)
  2471. {
  2472. POLYGON    *poly;
  2473. int npts;
  2474. int size;
  2475. int isopen;
  2476. char    *s;
  2477. if (!PointerIsValid(str))
  2478. elog(ERROR, " Bad (null) polygon external representation");
  2479. if ((npts = pair_count(str, ',')) <= 0)
  2480. elog(ERROR, "Bad polygon external representation '%s'", str);
  2481. size = offsetof(POLYGON, p[0]) +(sizeof(poly->p[0]) * npts);
  2482. poly = palloc(size);
  2483. MemSet((char *) poly, 0, size); /* zero any holes */
  2484. poly->size = size;
  2485. poly->npts = npts;
  2486. if ((!path_decode(FALSE, npts, str, &isopen, &s, &(poly->p[0])))
  2487. || (*s != ''))
  2488. elog(ERROR, "Bad polygon external representation '%s'", str);
  2489. make_bound_box(poly);
  2490. return poly;
  2491. } /* poly_in() */
  2492. /*---------------------------------------------------------------
  2493.  * poly_out - convert internal POLYGON representation to the
  2494.  *   character string format "((f8,f8),...,(f8,f8))"
  2495.  *   also support old format "(f8,f8,...,f8,f8)"
  2496.  *---------------------------------------------------------------*/
  2497. char *
  2498. poly_out(POLYGON *poly)
  2499. {
  2500. if (!PointerIsValid(poly))
  2501. return NULL;
  2502. return path_encode(TRUE, poly->npts, &(poly->p[0]));
  2503. } /* poly_out() */
  2504. /*-------------------------------------------------------
  2505.  * Is polygon A strictly left of polygon B? i.e. is
  2506.  * the right most point of A left of the left most point
  2507.  * of B?
  2508.  *-------------------------------------------------------*/
  2509. bool
  2510. poly_left(POLYGON *polya, POLYGON *polyb)
  2511. {
  2512. return polya->boundbox.high.x < polyb->boundbox.low.x;
  2513. }
  2514. /*-------------------------------------------------------
  2515.  * Is polygon A overlapping or left of polygon B? i.e. is
  2516.  * the left most point of A left of the right most point
  2517.  * of B?
  2518.  *-------------------------------------------------------*/
  2519. bool
  2520. poly_overleft(POLYGON *polya, POLYGON *polyb)
  2521. {
  2522. return polya->boundbox.low.x <= polyb->boundbox.high.x;
  2523. }
  2524. /*-------------------------------------------------------
  2525.  * Is polygon A strictly right of polygon B? i.e. is
  2526.  * the left most point of A right of the right most point
  2527.  * of B?
  2528.  *-------------------------------------------------------*/
  2529. bool
  2530. poly_right(POLYGON *polya, POLYGON *polyb)
  2531. {
  2532. return polya->boundbox.low.x > polyb->boundbox.high.x;
  2533. }
  2534. /*-------------------------------------------------------
  2535.  * Is polygon A overlapping or right of polygon B? i.e. is
  2536.  * the right most point of A right of the left most point
  2537.  * of B?
  2538.  *-------------------------------------------------------*/
  2539. bool
  2540. poly_overright(POLYGON *polya, POLYGON *polyb)
  2541. {
  2542. return polya->boundbox.high.x > polyb->boundbox.low.x;
  2543. }
  2544. /*-------------------------------------------------------
  2545.  * Is polygon A the same as polygon B? i.e. are all the
  2546.  * points the same?
  2547.  * Check all points for matches in both forward and reverse
  2548.  * direction since polygons are non-directional and are
  2549.  * closed shapes.
  2550.  *-------------------------------------------------------*/
  2551. bool
  2552. poly_same(POLYGON *polya, POLYGON *polyb)
  2553. {
  2554. if (!PointerIsValid(polya) || !PointerIsValid(polyb))
  2555. return FALSE;
  2556. if (polya->npts != polyb->npts)
  2557. return FALSE;
  2558. return plist_same(polya->npts, polya->p, polyb->p);
  2559. #ifdef NOT_USED
  2560. for (i = 0; i < polya->npts; i++)
  2561. {
  2562. if ((polya->p[i].x != polyb->p[i].x)
  2563. || (polya->p[i].y != polyb->p[i].y))
  2564. return FALSE;
  2565. }
  2566. return TRUE;
  2567. #endif
  2568. } /* poly_same() */
  2569. /*-----------------------------------------------------------------
  2570.  * Determine if polygon A overlaps polygon B by determining if
  2571.  * their bounding boxes overlap.
  2572.  *-----------------------------------------------------------------*/
  2573. bool
  2574. poly_overlap(POLYGON *polya, POLYGON *polyb)
  2575. {
  2576. return box_overlap(&(polya->boundbox), &(polyb->boundbox));
  2577. }
  2578. /*-----------------------------------------------------------------
  2579.  * Determine if polygon A contains polygon B by determining if A's
  2580.  * bounding box contains B's bounding box.
  2581.  *-----------------------------------------------------------------*/
  2582. #ifdef NOT_USED
  2583. bool
  2584. poly_contain(POLYGON *polya, POLYGON *polyb)
  2585. {
  2586. return box_contain(&(polya->boundbox), &(polyb->boundbox));
  2587. }
  2588. #endif
  2589. bool
  2590. poly_contain(POLYGON *polya, POLYGON *polyb)
  2591. {
  2592. int i;
  2593. if (!PointerIsValid(polya) || !PointerIsValid(polyb))
  2594. return FALSE;
  2595. if (box_contain(&(polya->boundbox), &(polyb->boundbox)))
  2596. {
  2597. for (i = 0; i < polyb->npts; i++)
  2598. {
  2599. if (point_inside(&(polyb->p[i]), polya->npts, &(polya->p[0])) == 0)
  2600. {
  2601. #if GEODEBUG
  2602. printf("poly_contain- point (%f,%f) not in polygonn", polyb->p[i].x, polyb->p[i].y);
  2603. #endif
  2604. return FALSE;
  2605. }
  2606. }
  2607. for (i = 0; i < polya->npts; i++)
  2608. {
  2609. if (point_inside(&(polya->p[i]), polyb->npts, &(polyb->p[0])) == 1)
  2610. {
  2611. #if GEODEBUG
  2612. printf("poly_contain- point (%f,%f) in polygonn", polya->p[i].x, polya->p[i].y);
  2613. #endif
  2614. return FALSE;
  2615. }
  2616. }
  2617. return TRUE;
  2618. }
  2619. #if GEODEBUG
  2620. printf("poly_contain- bound box ((%f,%f),(%f,%f)) not inside ((%f,%f),(%f,%f))n",
  2621.    polyb->boundbox.low.x, polyb->boundbox.low.y, polyb->boundbox.high.x, polyb->boundbox.high.y,
  2622.    polya->boundbox.low.x, polya->boundbox.low.y, polya->boundbox.high.x, polya->boundbox.high.y);
  2623. #endif
  2624. return FALSE;
  2625. } /* poly_contain() */
  2626. /*-----------------------------------------------------------------
  2627.  * Determine if polygon A is contained by polygon B by determining
  2628.  * if A's bounding box is contained by B's bounding box.
  2629.  *-----------------------------------------------------------------*/
  2630. #ifdef NOT_USED
  2631. bool
  2632. poly_contained(POLYGON *polya, POLYGON *polyb)
  2633. {
  2634. return box_contained(&(polya->boundbox), &(polyb->boundbox));
  2635. }
  2636. #endif
  2637. bool
  2638. poly_contained(POLYGON *polya, POLYGON *polyb)
  2639. {
  2640. return poly_contain(polyb, polya);
  2641. } /* poly_contained() */
  2642. /* poly_contain_pt()
  2643.  * Test to see if the point is inside the polygon.
  2644.  * Code adapted from integer-based routines in
  2645.  * Wn: A Server for the HTTP
  2646.  * File: wn/image.c
  2647.  * Version 1.15.1
  2648.  * Copyright (C) 1995 <by John Franks>
  2649.  * (code offered for use by J. Franks in Linux Journal letter.)
  2650.  */
  2651. bool
  2652. poly_contain_pt(POLYGON *poly, Point *p)
  2653. {
  2654. if (!PointerIsValid(poly) || !PointerIsValid(p))
  2655. return FALSE;
  2656. return point_inside(p, poly->npts, &(poly->p[0])) != 0;
  2657. } /* poly_contain_pt() */
  2658. bool
  2659. pt_contained_poly(Point *p, POLYGON *poly)
  2660. {
  2661. if (!PointerIsValid(p) || !PointerIsValid(poly))
  2662. return FALSE;
  2663. return poly_contain_pt(poly, p);
  2664. } /* pt_contained_poly() */
  2665. double *
  2666. poly_distance(POLYGON *polya, POLYGON *polyb)
  2667. {
  2668. double    *result;
  2669. if (!PointerIsValid(polya) || !PointerIsValid(polyb))
  2670. return NULL;
  2671. result = palloc(sizeof(double));
  2672. *result = 0;
  2673. return result;
  2674. } /* poly_distance() */
  2675. /***********************************************************************
  2676.  **
  2677.  ** Routines for 2D points.
  2678.  **
  2679.  ***********************************************************************/
  2680. Point *
  2681. point(float8 *x, float8 *y)
  2682. {
  2683. if (!(PointerIsValid(x) && PointerIsValid(y)))
  2684. return NULL;
  2685. return point_construct(*x, *y);
  2686. } /* point() */
  2687. Point *
  2688. point_add(Point *p1, Point *p2)
  2689. {
  2690. Point    *result;
  2691. if (!(PointerIsValid(p1) && PointerIsValid(p2)))
  2692. return NULL;
  2693. result = palloc(sizeof(Point));
  2694. result->x = (p1->x + p2->x);
  2695. result->y = (p1->y + p2->y);
  2696. return result;
  2697. } /* point_add() */
  2698. Point *
  2699. point_sub(Point *p1, Point *p2)
  2700. {
  2701. Point    *result;
  2702. if (!(PointerIsValid(p1) && PointerIsValid(p2)))
  2703. return NULL;
  2704. result = palloc(sizeof(Point));
  2705. result->x = (p1->x - p2->x);
  2706. result->y = (p1->y - p2->y);
  2707. return result;
  2708. } /* point_sub() */
  2709. Point *
  2710. point_mul(Point *p1, Point *p2)
  2711. {
  2712. Point    *result;
  2713. if (!(PointerIsValid(p1) && PointerIsValid(p2)))
  2714. return NULL;
  2715. result = palloc(sizeof(Point));
  2716. result->x = (p1->x * p2->x) - (p1->y * p2->y);
  2717. result->y = (p1->x * p2->y) + (p1->y * p2->x);
  2718. return result;
  2719. } /* point_mul() */
  2720. Point *
  2721. point_div(Point *p1, Point *p2)
  2722. {
  2723. Point    *result;
  2724. double div;
  2725. if (!(PointerIsValid(p1) && PointerIsValid(p2)))
  2726. return NULL;
  2727. result = palloc(sizeof(Point));
  2728. div = (p2->x * p2->x) + (p2->y * p2->y);
  2729. if (div == 0.0)
  2730. elog(ERROR, "point_div:  divide by 0.0 error");
  2731. result->x = ((p1->x * p2->x) + (p1->y * p2->y)) / div;
  2732. result->y = ((p2->x * p1->y) - (p2->y * p1->x)) / div;
  2733. return result;
  2734. } /* point_div() */
  2735. /***********************************************************************
  2736.  **
  2737.  ** Routines for 2D boxes.
  2738.  **
  2739.  ***********************************************************************/
  2740. BOX *
  2741. box(Point *p1, Point *p2)
  2742. {
  2743. BOX    *result;
  2744. if (!(PointerIsValid(p1) && PointerIsValid(p2)))
  2745. return NULL;
  2746. result = box_construct(p1->x, p2->x, p1->y, p2->y);
  2747. return result;
  2748. } /* box() */
  2749. BOX *
  2750. box_add(BOX *box, Point *p)
  2751. {
  2752. BOX    *result;
  2753. if (!(PointerIsValid(box) && PointerIsValid(p)))
  2754. return NULL;
  2755. result = box_construct((box->high.x + p->x), (box->low.x + p->x),
  2756.    (box->high.y + p->y), (box->low.y + p->y));
  2757. return result;
  2758. } /* box_add() */
  2759. BOX *
  2760. box_sub(BOX *box, Point *p)
  2761. {
  2762. BOX    *result;
  2763. if (!(PointerIsValid(box) && PointerIsValid(p)))
  2764. return NULL;
  2765. result = box_construct((box->high.x - p->x), (box->low.x - p->x),
  2766.    (box->high.y - p->y), (box->low.y - p->y));
  2767. return result;
  2768. } /* box_sub() */
  2769. BOX *
  2770. box_mul(BOX *box, Point *p)
  2771. {
  2772. BOX    *result;
  2773. Point    *high,
  2774.    *low;
  2775. if (!(PointerIsValid(box) && PointerIsValid(p)))
  2776. return NULL;
  2777. high = point_mul(&box->high, p);
  2778. low = point_mul(&box->low, p);
  2779. result = box_construct(high->x, low->x, high->y, low->y);
  2780. pfree(high);
  2781. pfree(low);
  2782. return result;
  2783. } /* box_mul() */
  2784. BOX *
  2785. box_div(BOX *box, Point *p)
  2786. {
  2787. BOX    *result;
  2788. Point    *high,
  2789.    *low;
  2790. if (!(PointerIsValid(box) && PointerIsValid(p)))
  2791. return NULL;
  2792. high = point_div(&box->high, p);
  2793. low = point_div(&box->low, p);
  2794. result = box_construct(high->x, low->x, high->y, low->y);
  2795. pfree(high);
  2796. pfree(low);
  2797. return result;
  2798. } /* box_div() */
  2799. /***********************************************************************
  2800.  **
  2801.  ** Routines for 2D paths.
  2802.  **
  2803.  ***********************************************************************/
  2804. /* path_add()
  2805.  * Concatenate two paths (only if they are both open).
  2806.  */
  2807. PATH *
  2808. path_add(PATH *p1, PATH *p2)
  2809. {
  2810. PATH    *result;
  2811. int size;
  2812. int i;
  2813. if (!(PointerIsValid(p1) && PointerIsValid(p2))
  2814. || p1->closed || p2->closed)
  2815. return NULL;
  2816. size = offsetof(PATH, p[0]) +(sizeof(p1->p[0]) * (p1->npts + p2->npts));
  2817. result = palloc(size);
  2818. result->size = size;
  2819. result->npts = (p1->npts + p2->npts);
  2820. result->closed = p1->closed;
  2821. for (i = 0; i < p1->npts; i++)
  2822. {
  2823. result->p[i].x = p1->p[i].x;
  2824. result->p[i].y = p1->p[i].y;
  2825. }
  2826. for (i = 0; i < p2->npts; i++)
  2827. {
  2828. result->p[i + p1->npts].x = p2->p[i].x;
  2829. result->p[i + p1->npts].y = p2->p[i].y;
  2830. }
  2831. return result;
  2832. } /* path_add() */
  2833. /* path_add_pt()
  2834.  * Translation operator.
  2835.  */
  2836. PATH *
  2837. path_add_pt(PATH *path, Point *point)
  2838. {
  2839. PATH    *result;
  2840. int i;
  2841. if ((!PointerIsValid(path)) || (!PointerIsValid(point)))
  2842. return NULL;
  2843. result = path_copy(path);
  2844. for (i = 0; i < path->npts; i++)
  2845. {
  2846. result->p[i].x += point->x;
  2847. result->p[i].y += point->y;
  2848. }
  2849. return result;
  2850. } /* path_add_pt() */
  2851. PATH *
  2852. path_sub_pt(PATH *path, Point *point)
  2853. {
  2854. PATH    *result;
  2855. int i;
  2856. if ((!PointerIsValid(path)) || (!PointerIsValid(point)))
  2857. return NULL;
  2858. result = path_copy(path);
  2859. for (i = 0; i < path->npts; i++)
  2860. {
  2861. result->p[i].x -= point->x;
  2862. result->p[i].y -= point->y;
  2863. }
  2864. return result;
  2865. } /* path_sub_pt() */
  2866. /* path_mul_pt()
  2867.  * Rotation and scaling operators.
  2868.  */
  2869. PATH *
  2870. path_mul_pt(PATH *path, Point *point)
  2871. {
  2872. PATH    *result;
  2873. Point    *p;
  2874. int i;
  2875. if ((!PointerIsValid(path)) || (!PointerIsValid(point)))
  2876. return NULL;
  2877. result = path_copy(path);
  2878. for (i = 0; i < path->npts; i++)
  2879. {
  2880. p = point_mul(&path->p[i], point);
  2881. result->p[i].x = p->x;
  2882. result->p[i].y = p->y;
  2883. pfree(p);
  2884. }
  2885. return result;
  2886. } /* path_mul_pt() */
  2887. PATH *
  2888. path_div_pt(PATH *path, Point *point)
  2889. {
  2890. PATH    *result;
  2891. Point    *p;
  2892. int i;
  2893. if ((!PointerIsValid(path)) || (!PointerIsValid(point)))
  2894. return NULL;
  2895. result = path_copy(path);
  2896. for (i = 0; i < path->npts; i++)
  2897. {
  2898. p = point_div(&path->p[i], point);
  2899. result->p[i].x = p->x;
  2900. result->p[i].y = p->y;
  2901. pfree(p);
  2902. }
  2903. return result;
  2904. } /* path_div_pt() */
  2905. bool
  2906. path_contain_pt(PATH *path, Point *p)
  2907. {
  2908. if (!PointerIsValid(path) || !PointerIsValid(p))
  2909. return FALSE;
  2910. return (on_ppath(p, path));
  2911. } /* path_contain_pt() */
  2912. /* pt_contained_path
  2913.  * Point in or on path? This is the same as on_ppath.
  2914.  * - thomas 1998-10-29
  2915.  */
  2916. bool
  2917. pt_contained_path(Point *p, PATH *path)
  2918. {
  2919. if (!PointerIsValid(p) || !PointerIsValid(path))
  2920. return FALSE;
  2921. return path_contain_pt(path, p);
  2922. } /* pt_contained_path() */
  2923. Point *
  2924. path_center(PATH *path)
  2925. {
  2926. Point    *result;
  2927. if (!PointerIsValid(path))
  2928. return NULL;
  2929. elog(ERROR, "path_center not implemented", NULL);
  2930. result = palloc(sizeof(Point));
  2931. result = NULL;
  2932. return result;
  2933. } /* path_center() */
  2934. POLYGON    *
  2935. path_poly(PATH *path)
  2936. {
  2937. POLYGON    *poly;
  2938. int size;
  2939. int i;
  2940. if (!PointerIsValid(path))
  2941. return NULL;
  2942. if (!path->closed)
  2943. elog(ERROR, "Open path cannot be converted to polygon", NULL);
  2944. size = offsetof(POLYGON, p[0]) +(sizeof(poly->p[0]) * path->npts);
  2945. poly = palloc(size);
  2946. poly->size = size;
  2947. poly->npts = path->npts;
  2948. for (i = 0; i < path->npts; i++)
  2949. {
  2950. poly->p[i].x = path->p[i].x;
  2951. poly->p[i].y = path->p[i].y;
  2952. }
  2953. make_bound_box(poly);
  2954. return poly;
  2955. } /* path_polygon() */
  2956. /* upgradepath()
  2957.  * Convert path read from old-style string into correct representation.
  2958.  *
  2959.  * Old-style: '(closed,#pts,x1,y1,...)' where closed is a boolean flag
  2960.  * New-style: '((x1,y1),...)' for closed path
  2961.  *   '[(x1,y1),...]' for open path
  2962.  */
  2963. PATH *
  2964. upgradepath(PATH *path)
  2965. {
  2966. PATH    *result;
  2967. int size,
  2968. npts;
  2969. int i;
  2970. if (!PointerIsValid(path) || (path->npts < 2))
  2971. return NULL;
  2972. if (!isoldpath(path))
  2973. elog(ERROR, "upgradepath: path already upgraded?", NULL);
  2974. npts = (path->npts - 1);
  2975. size = offsetof(PATH, p[0]) +(sizeof(path->p[0]) * npts);
  2976. result = palloc(size);
  2977. MemSet((char *) result, 0, size);
  2978. result->size = size;
  2979. result->npts = npts;
  2980. result->closed = (path->p[0].x != 0);
  2981. for (i = 0; i < result->npts; i++)
  2982. {
  2983. result->p[i].x = path->p[i + 1].x;
  2984. result->p[i].y = path->p[i + 1].y;
  2985. }
  2986. return result;
  2987. } /* upgradepath() */
  2988. bool
  2989. isoldpath(PATH *path)
  2990. {
  2991. if (!PointerIsValid(path) || (path->npts < 2))
  2992. return FALSE;
  2993. return path->npts == (path->p[0].y + 1);
  2994. } /* isoldpath() */
  2995. /***********************************************************************
  2996.  **
  2997.  ** Routines for 2D polygons.
  2998.  **
  2999.  ***********************************************************************/
  3000. int4
  3001. poly_npoints(POLYGON *poly)
  3002. {
  3003. if (!PointerIsValid(poly))
  3004. return FALSE;
  3005. return poly->npts;
  3006. } /* poly_npoints() */
  3007. Point *
  3008. poly_center(POLYGON *poly)
  3009. {
  3010. Point    *result;
  3011. CIRCLE    *circle;
  3012. if (!PointerIsValid(poly))
  3013. return NULL;
  3014. if (PointerIsValid(circle = poly_circle(poly)))
  3015. {
  3016. result = circle_center(circle);
  3017. pfree(circle);
  3018. }
  3019. else
  3020. result = NULL;
  3021. return result;
  3022. } /* poly_center() */
  3023. BOX *
  3024. poly_box(POLYGON *poly)
  3025. {
  3026. BOX    *box;
  3027. if (!PointerIsValid(poly) || (poly->npts < 1))
  3028. return NULL;
  3029. box = box_copy(&poly->boundbox);
  3030. return box;
  3031. } /* poly_box() */
  3032. /* box_poly()
  3033.  * Convert a box to a polygon.
  3034.  */
  3035. POLYGON    *
  3036. box_poly(BOX *box)
  3037. {
  3038. POLYGON    *poly;
  3039. int size;
  3040. if (!PointerIsValid(box))
  3041. return NULL;
  3042. /* map four corners of the box to a polygon */
  3043. size = offsetof(POLYGON, p[0]) +(sizeof(poly->p[0]) * 4);
  3044. poly = palloc(size);
  3045. poly->size = size;
  3046. poly->npts = 4;
  3047. poly->p[0].x = box->low.x;
  3048. poly->p[0].y = box->low.y;
  3049. poly->p[1].x = box->low.x;
  3050. poly->p[1].y = box->high.y;
  3051. poly->p[2].x = box->high.x;
  3052. poly->p[2].y = box->high.y;
  3053. poly->p[3].x = box->high.x;
  3054. poly->p[3].y = box->low.y;
  3055. box_fill(&poly->boundbox, box->high.x, box->low.x, box->high.y, box->low.y);
  3056. return poly;
  3057. } /* box_poly() */
  3058. PATH *
  3059. poly_path(POLYGON *poly)
  3060. {
  3061. PATH    *path;
  3062. int size;
  3063. int i;
  3064. if (!PointerIsValid(poly) || (poly->npts < 0))
  3065. return NULL;
  3066. size = offsetof(PATH, p[0]) +(sizeof(path->p[0]) * poly->npts);
  3067. path = palloc(size);
  3068. path->size = size;
  3069. path->npts = poly->npts;
  3070. path->closed = TRUE;
  3071. for (i = 0; i < poly->npts; i++)
  3072. {
  3073. path->p[i].x = poly->p[i].x;
  3074. path->p[i].y = poly->p[i].y;
  3075. }
  3076. return path;
  3077. } /* poly_path() */
  3078. /* upgradepoly()
  3079.  * Convert polygon read as pre-v6.1 string to new interpretation.
  3080.  * Old-style: '(x1,x2,...,y1,y2,...)'
  3081.  * New-style: '(x1,y1,x2,y2,...)'
  3082.  */
  3083. POLYGON    *
  3084. upgradepoly(POLYGON *poly)
  3085. {
  3086. POLYGON    *result;
  3087. int size;
  3088. int n2,
  3089. i,
  3090. ii;
  3091. if (!PointerIsValid(poly) || (poly->npts < 1))
  3092. return NULL;
  3093. size = offsetof(POLYGON, p[0]) +(sizeof(poly->p[0]) * poly->npts);
  3094. result = palloc(size);
  3095. MemSet((char *) result, 0, size);
  3096. result->size = size;
  3097. result->npts = poly->npts;
  3098. n2 = poly->npts / 2;
  3099. for (i = 0; i < n2; i++)
  3100. {
  3101. result->p[2 * i].x = poly->p[i].x; /* even indices */
  3102. result->p[2 * i + 1].x = poly->p[i].y; /* odd indices */
  3103. }
  3104. if ((ii = ((poly->npts % 2) ? 1 : 0)))
  3105. {
  3106. result->p[poly->npts - 1].x = poly->p[n2].x;
  3107. result->p[0].y = poly->p[n2].y;
  3108. }
  3109. for (i = 0; i < n2; i++)
  3110. {
  3111. result->p[2 * i + ii].y = poly->p[i + n2 + ii].x; /* even (+offset)
  3112.  * indices */
  3113. result->p[2 * i + ii + 1].y = poly->p[i + n2 + ii].y; /* odd (+offset) indices */
  3114. }
  3115. return result;
  3116. } /* upgradepoly() */
  3117. /* revertpoly()
  3118.  * Reverse effect of upgradepoly().
  3119.  */
  3120. POLYGON    *
  3121. revertpoly(POLYGON *poly)
  3122. {
  3123. POLYGON    *result;
  3124. int size;
  3125. int n2,
  3126. i,
  3127. ii;
  3128. if (!PointerIsValid(poly) || (poly->npts < 1))
  3129. return NULL;
  3130. size = offsetof(POLYGON, p[0]) +(sizeof(poly->p[0]) * poly->npts);
  3131. result = palloc(size);
  3132. MemSet((char *) result, 0, size);
  3133. result->size = size;
  3134. result->npts = poly->npts;
  3135. n2 = poly->npts / 2;
  3136. for (i = 0; i < n2; i++)
  3137. {
  3138. result->p[i].x = poly->p[2 * i].x; /* even indices */
  3139. result->p[i].y = poly->p[2 * i + 1].x; /* odd indices */
  3140. }
  3141. if ((ii = ((poly->npts % 2) ? 1 : 0)))
  3142. {
  3143. result->p[n2].x = poly->p[poly->npts - 1].x;
  3144. result->p[n2].y = poly->p[0].y;
  3145. }
  3146. for (i = 0; i < n2; i++)
  3147. {
  3148. result->p[i + n2 + ii].x = poly->p[2 * i + ii].y; /* even (+offset)
  3149.  * indices */
  3150. result->p[i + n2 + ii].y = poly->p[2 * i + ii + 1].y; /* odd (+offset) indices */
  3151. }
  3152. return result;
  3153. } /* revertpoly() */
  3154. /***********************************************************************
  3155.  **
  3156.  ** Routines for circles.
  3157.  **
  3158.  ***********************************************************************/
  3159. /*----------------------------------------------------------
  3160.  * Formatting and conversion routines.
  3161.  *---------------------------------------------------------*/
  3162. /* circle_in - convert a string to internal form.
  3163.  *
  3164.  * External format: (center and radius of circle)
  3165.  * "((f8,f8)<f8>)"
  3166.  * also supports quick entry style "(f8,f8,f8)"
  3167.  */
  3168. CIRCLE *
  3169. circle_in(char *str)
  3170. {
  3171. CIRCLE    *circle;
  3172. char    *s,
  3173.    *cp;
  3174. int depth = 0;
  3175. if (!PointerIsValid(str))
  3176. elog(ERROR, " Bad (null) circle external representation", NULL);
  3177. circle = palloc(sizeof(CIRCLE));
  3178. s = str;
  3179. while (isspace(*s))
  3180. s++;
  3181. if ((*s == LDELIM_C) || (*s == LDELIM))
  3182. {
  3183. depth++;
  3184. cp = (s + 1);
  3185. while (isspace(*cp))
  3186. cp++;
  3187. if (*cp == LDELIM)
  3188. s = cp;
  3189. }
  3190. if (!pair_decode(s, &circle->center.x, &circle->center.y, &s))
  3191. elog(ERROR, "Bad circle external representation '%s'", str);
  3192. if (*s == DELIM)
  3193. s++;
  3194. while (isspace(*s))
  3195. s++;
  3196. if ((!single_decode(s, &circle->radius, &s)) || (circle->radius < 0))
  3197. elog(ERROR, "Bad circle external representation '%s'", str);
  3198. while (depth > 0)
  3199. {
  3200. if ((*s == RDELIM)
  3201. || ((*s == RDELIM_C) && (depth == 1)))
  3202. {
  3203. depth--;
  3204. s++;
  3205. while (isspace(*s))
  3206. s++;
  3207. }
  3208. else
  3209. elog(ERROR, "Bad circle external representation '%s'", str);
  3210. }
  3211. if (*s != '')
  3212. elog(ERROR, "Bad circle external representation '%s'", str);
  3213. return circle;
  3214. } /* circle_in() */
  3215. /* circle_out - convert a circle to external form.
  3216.  */
  3217. char *
  3218. circle_out(CIRCLE *circle)
  3219. {
  3220. char    *result;
  3221. char    *cp;
  3222. if (!PointerIsValid(circle))
  3223. return NULL;
  3224. result = palloc(3 * (P_MAXLEN + 1) + 3);
  3225. cp = result;
  3226. *cp++ = LDELIM_C;
  3227. *cp++ = LDELIM;
  3228. if (!pair_encode(circle->center.x, circle->center.y, cp))
  3229. elog(ERROR, "Unable to format circle", NULL);
  3230. cp += strlen(cp);
  3231. *cp++ = RDELIM;
  3232. *cp++ = DELIM;
  3233. if (!single_encode(circle->radius, cp))
  3234. elog(ERROR, "Unable to format circle", NULL);
  3235. cp += strlen(cp);
  3236. *cp++ = RDELIM_C;
  3237. *cp = '';
  3238. return result;
  3239. } /* circle_out() */
  3240. /*----------------------------------------------------------
  3241.  * Relational operators for CIRCLEs.
  3242.  * <, >, <=, >=, and == are based on circle area.
  3243.  *---------------------------------------------------------*/
  3244. /* circles identical?
  3245.  */
  3246. bool
  3247. circle_same(CIRCLE *circle1, CIRCLE *circle2)
  3248. {
  3249. return (FPeq(circle1->radius, circle2->radius)
  3250. && FPeq(circle1->center.x, circle2->center.x)
  3251. && FPeq(circle1->center.y, circle2->center.y));
  3252. } /* circle_same() */
  3253. /* circle_overlap - does circle1 overlap circle2?
  3254.  */
  3255. bool
  3256. circle_overlap(CIRCLE *circle1, CIRCLE *circle2)
  3257. {
  3258. return FPle(point_dt(&circle1->center, &circle2->center), (circle1->radius + circle2->radius));
  3259. }
  3260. /* circle_overleft - is the right edge of circle1 to the left of
  3261.  * the right edge of circle2?
  3262.  */
  3263. bool
  3264. circle_overleft(CIRCLE *circle1, CIRCLE *circle2)
  3265. {
  3266. return FPle((circle1->center.x + circle1->radius), (circle2->center.x + circle2->radius));
  3267. }
  3268. /* circle_left - is circle1 strictly left of circle2?
  3269.  */
  3270. bool
  3271. circle_left(CIRCLE *circle1, CIRCLE *circle2)
  3272. {
  3273. return FPle((circle1->center.x + circle1->radius), (circle2->center.x - circle2->radius));
  3274. }
  3275. /* circle_right - is circle1 strictly right of circle2?
  3276.  */
  3277. bool
  3278. circle_right(CIRCLE *circle1, CIRCLE *circle2)
  3279. {
  3280. return FPge((circle1->center.x - circle1->radius), (circle2->center.x + circle2->radius));
  3281. }
  3282. /* circle_overright - is the left edge of circle1 to the right of
  3283.  * the left edge of circle2?
  3284.  */
  3285. bool
  3286. circle_overright(CIRCLE *circle1, CIRCLE *circle2)
  3287. {
  3288. return FPge((circle1->center.x - circle1->radius), (circle2->center.x - circle2->radius));
  3289. }
  3290. /* circle_contained - is circle1 contained by circle2?
  3291.  */
  3292. bool
  3293. circle_contained(CIRCLE *circle1, CIRCLE *circle2)
  3294. {
  3295. return FPle((point_dt(&circle1->center, &circle2->center) + circle1->radius), circle2->radius);
  3296. }
  3297. /* circle_contain - does circle1 contain circle2?
  3298.  */
  3299. bool
  3300. circle_contain(CIRCLE *circle1, CIRCLE *circle2)
  3301. {
  3302. return FPle((point_dt(&circle1->center, &circle2->center) + circle2->radius), circle1->radius);
  3303. }
  3304. /* circle_positionop -
  3305.  * is circle1 entirely {above,below} circle2?
  3306.  */
  3307. bool
  3308. circle_below(CIRCLE *circle1, CIRCLE *circle2)
  3309. {
  3310. return FPle((circle1->center.y + circle1->radius), (circle2->center.y - circle2->radius));
  3311. }
  3312. bool
  3313. circle_above(CIRCLE *circle1, CIRCLE *circle2)
  3314. {
  3315. return FPge((circle1->center.y - circle1->radius), (circle2->center.y + circle2->radius));
  3316. }
  3317. /* circle_relop - is area(circle1) relop area(circle2), within
  3318.  * our accuracy constraint?
  3319.  */
  3320. bool
  3321. circle_eq(CIRCLE *circle1, CIRCLE *circle2)
  3322. {
  3323. return FPeq(circle_ar(circle1), circle_ar(circle2));
  3324. } /* circle_eq() */
  3325. bool
  3326. circle_ne(CIRCLE *circle1, CIRCLE *circle2)
  3327. {
  3328. return !circle_eq(circle1, circle2);
  3329. } /* circle_ne() */
  3330. bool
  3331. circle_lt(CIRCLE *circle1, CIRCLE *circle2)
  3332. {
  3333. return FPlt(circle_ar(circle1), circle_ar(circle2));
  3334. } /* circle_lt() */
  3335. bool
  3336. circle_gt(CIRCLE *circle1, CIRCLE *circle2)
  3337. {
  3338. return FPgt(circle_ar(circle1), circle_ar(circle2));
  3339. } /* circle_gt() */
  3340. bool
  3341. circle_le(CIRCLE *circle1, CIRCLE *circle2)
  3342. {
  3343. return FPle(circle_ar(circle1), circle_ar(circle2));
  3344. } /* circle_le() */
  3345. bool
  3346. circle_ge(CIRCLE *circle1, CIRCLE *circle2)
  3347. {
  3348. return FPge(circle_ar(circle1), circle_ar(circle2));
  3349. } /* circle_ge() */
  3350. /*----------------------------------------------------------
  3351.  * "Arithmetic" operators on circles.
  3352.  * circle_foo returns foo as an object (pointer) that
  3353.  can be passed between languages.
  3354.  * circle_xx is an internal routine which returns the
  3355.  * actual value.
  3356.  *---------------------------------------------------------*/
  3357. static CIRCLE *
  3358. circle_copy(CIRCLE *circle)
  3359. {
  3360. CIRCLE    *result;
  3361. if (!PointerIsValid(circle))
  3362. return NULL;
  3363. result = palloc(sizeof(CIRCLE));
  3364. memmove((char *) result, (char *) circle, sizeof(CIRCLE));
  3365. return result;
  3366. } /* circle_copy() */
  3367. /* circle_add_pt()
  3368.  * Translation operator.
  3369.  */
  3370. CIRCLE *
  3371. circle_add_pt(CIRCLE *circle, Point *point)
  3372. {
  3373. CIRCLE    *result;
  3374. if (!PointerIsValid(circle) || !PointerIsValid(point))
  3375. return NULL;
  3376. result = circle_copy(circle);
  3377. result->center.x += point->x;
  3378. result->center.y += point->y;
  3379. return result;
  3380. } /* circle_add_pt() */
  3381. CIRCLE *
  3382. circle_sub_pt(CIRCLE *circle, Point *point)
  3383. {
  3384. CIRCLE    *result;
  3385. if (!PointerIsValid(circle) || !PointerIsValid(point))
  3386. return NULL;
  3387. result = circle_copy(circle);
  3388. result->center.x -= point->x;
  3389. result->center.y -= point->y;
  3390. return result;
  3391. } /* circle_sub_pt() */
  3392. /* circle_mul_pt()
  3393.  * Rotation and scaling operators.
  3394.  */
  3395. CIRCLE *
  3396. circle_mul_pt(CIRCLE *circle, Point *point)
  3397. {
  3398. CIRCLE    *result;
  3399. Point    *p;
  3400. if (!PointerIsValid(circle) || !PointerIsValid(point))
  3401. return NULL;
  3402. result = circle_copy(circle);
  3403. p = point_mul(&circle->center, point);
  3404. result->center.x = p->x;
  3405. result->center.y = p->y;
  3406. pfree(p);
  3407. result->radius *= HYPOT(point->x, point->y);
  3408. return result;
  3409. } /* circle_mul_pt() */
  3410. CIRCLE *
  3411. circle_div_pt(CIRCLE *circle, Point *point)
  3412. {
  3413. CIRCLE    *result;
  3414. Point    *p;
  3415. if (!PointerIsValid(circle) || !PointerIsValid(point))
  3416. return NULL;
  3417. result = circle_copy(circle);
  3418. p = point_div(&circle->center, point);
  3419. result->center.x = p->x;
  3420. result->center.y = p->y;
  3421. pfree(p);
  3422. result->radius /= HYPOT(point->x, point->y);
  3423. return result;
  3424. } /* circle_div_pt() */
  3425. /* circle_area - returns the area of the circle.
  3426.  */
  3427. double *
  3428. circle_area(CIRCLE *circle)
  3429. {
  3430. double    *result;
  3431. result = palloc(sizeof(double));
  3432. *result = circle_ar(circle);
  3433. return result;
  3434. }
  3435. /* circle_diameter - returns the diameter of the circle.
  3436.  */
  3437. double *
  3438. circle_diameter(CIRCLE *circle)
  3439. {
  3440. double    *result;
  3441. result = palloc(sizeof(double));
  3442. *result = (2 * circle->radius);
  3443. return result;
  3444. }
  3445. /* circle_radius - returns the radius of the circle.
  3446.  */
  3447. double *
  3448. circle_radius(CIRCLE *circle)
  3449. {
  3450. double    *result;
  3451. result = palloc(sizeof(double));
  3452. *result = circle->radius;
  3453. return result;
  3454. }
  3455. /* circle_distance - returns the distance between
  3456.  *   two circles.
  3457.  */
  3458. double *
  3459. circle_distance(CIRCLE *circle1, CIRCLE *circle2)
  3460. {
  3461. double    *result;
  3462. result = palloc(sizeof(double));
  3463. *result = (point_dt(&circle1->center, &circle2->center)
  3464.    - (circle1->radius + circle2->radius));
  3465. if (*result < 0)
  3466. *result = 0;
  3467. return result;
  3468. } /* circle_distance() */
  3469. bool
  3470. circle_contain_pt(CIRCLE *circle, Point *point)
  3471. {
  3472. bool within;
  3473. double    *d;
  3474. if (!PointerIsValid(circle) || !PointerIsValid(point))
  3475. return FALSE;
  3476. d = point_distance(&(circle->center), point);
  3477. within = (*d <= circle->radius);
  3478. pfree(d);
  3479. return within;
  3480. } /* circle_contain_pt() */
  3481. bool
  3482. pt_contained_circle(Point *point, CIRCLE *circle)
  3483. {
  3484. return circle_contain_pt(circle, point);
  3485. } /* circle_contain_pt() */
  3486. /* dist_pc - returns the distance between
  3487.  *   a point and a circle.
  3488.  */
  3489. double *
  3490. dist_pc(Point *point, CIRCLE *circle)
  3491. {
  3492. double    *result;
  3493. result = palloc(sizeof(double));
  3494. *result = (point_dt(point, &circle->center) - circle->radius);
  3495. if (*result < 0)
  3496. *result = 0;
  3497. return result;
  3498. } /* dist_pc() */
  3499. /* circle_center - returns the center point of the circle.
  3500.  */
  3501. Point *
  3502. circle_center(CIRCLE *circle)
  3503. {
  3504. Point    *result;
  3505. result = palloc(sizeof(Point));
  3506. result->x = circle->center.x;
  3507. result->y = circle->center.y;
  3508. return result;
  3509. }
  3510. /* circle_ar - returns the area of the circle.
  3511.  */
  3512. static double
  3513. circle_ar(CIRCLE *circle)
  3514. {
  3515. return PI * (circle->radius * circle->radius);
  3516. }
  3517. /* circle_dt - returns the distance between the
  3518.  *   center points of two circlees.
  3519.  */
  3520. #ifdef NOT_USED
  3521. double
  3522. circle_dt(CIRCLE *circle1, CIRCLE *circle2)
  3523. {
  3524. double result;
  3525. result = point_dt(&circle1->center, &circle2->center);
  3526. return result;
  3527. }
  3528. #endif
  3529. /*----------------------------------------------------------
  3530.  * Conversion operators.
  3531.  *---------------------------------------------------------*/
  3532. CIRCLE *
  3533. circle(Point *center, float8 *radius)
  3534. {
  3535. CIRCLE    *result;
  3536. if (!(PointerIsValid(center) && PointerIsValid(radius)))
  3537. return NULL;
  3538. result = palloc(sizeof(CIRCLE));
  3539. result->center.x = center->x;
  3540. result->center.y = center->y;
  3541. result->radius = *radius;
  3542. return result;
  3543. }
  3544. BOX *
  3545. circle_box(CIRCLE *circle)
  3546. {
  3547. BOX    *box;
  3548. double delta;
  3549. if (!PointerIsValid(circle))
  3550. return NULL;
  3551. box = palloc(sizeof(BOX));
  3552. delta = circle->radius / sqrt(2.0e0);
  3553. box->high.x = circle->center.x + delta;
  3554. box->low.x = circle->center.x - delta;
  3555. box->high.y = circle->center.y + delta;
  3556. box->low.y = circle->center.y - delta;
  3557. return box;
  3558. } /* circle_box() */
  3559. /* box_circle()
  3560.  * Convert a box to a circle.
  3561.  */
  3562. CIRCLE *
  3563. box_circle(BOX *box)
  3564. {
  3565. CIRCLE    *circle;
  3566. if (!PointerIsValid(box))
  3567. return NULL;
  3568. circle = palloc(sizeof(CIRCLE));
  3569. circle->center.x = (box->high.x + box->low.x) / 2;
  3570. circle->center.y = (box->high.y + box->low.y) / 2;
  3571. circle->radius = point_dt(&circle->center, &box->high);
  3572. return circle;
  3573. } /* box_circle() */
  3574. POLYGON    *
  3575. circle_poly(int npts, CIRCLE *circle)
  3576. {
  3577. POLYGON    *poly;
  3578. int size;
  3579. int i;
  3580. double angle;
  3581. if (!PointerIsValid(circle))
  3582. return NULL;
  3583. if (FPzero(circle->radius) || (npts < 2))
  3584. elog(ERROR, "Unable to convert circle to polygon", NULL);
  3585. size = offsetof(POLYGON, p[0]) +(sizeof(poly->p[0]) * npts);
  3586. poly = palloc(size);
  3587. MemSet((char *) poly, 0, size); /* zero any holes */
  3588. poly->size = size;
  3589. poly->npts = npts;
  3590. for (i = 0; i < npts; i++)
  3591. {
  3592. angle = i * (2 * PI / npts);
  3593. poly->p[i].x = circle->center.x - (circle->radius * cos(angle));
  3594. poly->p[i].y = circle->center.y + (circle->radius * sin(angle));
  3595. }
  3596. make_bound_box(poly);
  3597. return poly;
  3598. }
  3599. /* poly_circle - convert polygon to circle
  3600.  *
  3601.  * XXX This algorithm should use weighted means of line segments
  3602.  * rather than straight average values of points - tgl 97/01/21.
  3603.  */
  3604. CIRCLE *
  3605. poly_circle(POLYGON *poly)
  3606. {
  3607. CIRCLE    *circle;
  3608. int i;
  3609. if (!PointerIsValid(poly))
  3610. return NULL;
  3611. if (poly->npts < 2)
  3612. elog(ERROR, "Unable to convert polygon to circle", NULL);
  3613. circle = palloc(sizeof(CIRCLE));
  3614. circle->center.x = 0;
  3615. circle->center.y = 0;
  3616. circle->radius = 0;
  3617. for (i = 0; i < poly->npts; i++)
  3618. {
  3619. circle->center.x += poly->p[i].x;
  3620. circle->center.y += poly->p[i].y;
  3621. }
  3622. circle->center.x /= poly->npts;
  3623. circle->center.y /= poly->npts;
  3624. for (i = 0; i < poly->npts; i++)
  3625. circle->radius += point_dt(&poly->p[i], &circle->center);
  3626. circle->radius /= poly->npts;
  3627. if (FPzero(circle->radius))
  3628. elog(ERROR, "Unable to convert polygon to circle", NULL);
  3629. return circle;
  3630. } /* poly_circle() */
  3631. /***********************************************************************
  3632.  **
  3633.  ** Private routines for multiple types.
  3634.  **
  3635.  ***********************************************************************/
  3636. #define HIT_IT INT_MAX
  3637. static int
  3638. point_inside(Point *p, int npts, Point *plist)
  3639. {
  3640. double x0,
  3641. y0;
  3642. double px,
  3643. py;
  3644. int i;
  3645. double x,
  3646. y;
  3647. int cross,
  3648. crossnum;
  3649. /*
  3650.  * We calculate crossnum, which is twice the crossing number of a
  3651.  * ray from the origin parallel to the positive X axis.
  3652.  * A coordinate change is made to move the test point to the origin.
  3653.  * Then the function lseg_crossing() is called to calculate the crossnum of
  3654.  * one segment of the translated polygon with the ray which is the
  3655.  * positive X-axis.
  3656.  */
  3657. crossnum = 0;
  3658. i = 0;
  3659. if (npts <= 0)
  3660. return 0;
  3661. x0 = plist[0].x - p->x;
  3662. y0 = plist[0].y - p->y;
  3663. px = x0;
  3664. py = y0;
  3665. for (i = 1; i < npts; i++)
  3666. {
  3667. x = plist[i].x - p->x;
  3668. y = plist[i].y - p->y;
  3669. if ((cross = lseg_crossing(x, y, px, py)) == HIT_IT)
  3670. return 2;
  3671. crossnum += cross;
  3672. px = x;
  3673. py = y;
  3674. }
  3675. if ((cross = lseg_crossing(x0, y0, px, py)) == HIT_IT)
  3676. return 2;
  3677. crossnum += cross;
  3678. if (crossnum != 0)
  3679. return 1;
  3680. return 0;
  3681. } /* point_inside() */
  3682. /* lseg_crossing()
  3683.  * The function lseg_crossing() returns +2, or -2 if the segment from (x,y)
  3684.  * to previous (x,y) crosses the positive X-axis positively or negatively.
  3685.  * It returns +1 or -1 if one endpoint is on this ray, or 0 if both are.
  3686.  * It returns 0 if the ray and the segment don't intersect.
  3687.  * It returns HIT_IT if the segment contains (0,0)
  3688.  */
  3689. static int
  3690. lseg_crossing(double x, double y, double px, double py)
  3691. {
  3692. double z;
  3693. int sgn;
  3694. /* If (px,py) = (0,0) and not first call we have already sent HIT_IT */
  3695. if (FPzero(y))
  3696. {
  3697. if (FPzero(x))
  3698. {
  3699. return HIT_IT;
  3700. }
  3701. else if (FPgt(x, 0))
  3702. {
  3703. if (FPzero(py))
  3704. return FPgt(px, 0) ? 0 : HIT_IT;
  3705. return FPlt(py, 0) ? 1 : -1;
  3706. }
  3707. else
  3708. { /* x < 0 */
  3709. if (FPzero(py))
  3710. return FPlt(px, 0) ? 0 : HIT_IT;
  3711. return 0;
  3712. }
  3713. }
  3714. /* Now we know y != 0; set sgn to sign of y */
  3715. sgn = (FPgt(y, 0) ? 1 : -1);
  3716. if (FPzero(py))
  3717. return FPlt(px, 0) ? 0 : sgn;
  3718. if (FPgt((sgn * py), 0))
  3719. { /* y and py have same sign */
  3720. return 0;
  3721. }
  3722. else
  3723. { /* y and py have opposite signs */
  3724. if (FPge(x, 0) && FPgt(px, 0))
  3725. return 2 * sgn;
  3726. if (FPlt(x, 0) && FPle(px, 0))
  3727. return 0;
  3728. z = (x - px) * y - (y - py) * x;
  3729. if (FPzero(z))
  3730. return HIT_IT;
  3731. return FPgt((sgn * z), 0) ? 0 : 2 * sgn;
  3732. }
  3733. } /* lseg_crossing() */
  3734. static bool
  3735. plist_same(int npts, Point *p1, Point *p2)
  3736. {
  3737. int i,
  3738. ii,
  3739. j;
  3740. /* find match for first point */
  3741. for (i = 0; i < npts; i++)
  3742. {
  3743. if ((FPeq(p2[i].x, p1[0].x))
  3744. && (FPeq(p2[i].y, p1[0].y)))
  3745. {
  3746. /* match found? then look forward through remaining points */
  3747. for (ii = 1, j = i + 1; ii < npts; ii++, j++)
  3748. {
  3749. if (j >= npts)
  3750. j = 0;
  3751. if ((!FPeq(p2[j].x, p1[ii].x))
  3752. || (!FPeq(p2[j].y, p1[ii].y)))
  3753. {
  3754. #ifdef GEODEBUG
  3755. printf("plist_same- %d failed forward match with %dn", j, ii);
  3756. #endif
  3757. break;
  3758. }
  3759. }
  3760. #ifdef GEODEBUG
  3761. printf("plist_same- ii = %d/%d after forward matchn", ii, npts);
  3762. #endif
  3763. if (ii == npts)
  3764. return TRUE;
  3765. /* match not found forwards? then look backwards */
  3766. for (ii = 1, j = i - 1; ii < npts; ii++, j--)
  3767. {
  3768. if (j < 0)
  3769. j = (npts - 1);
  3770. if ((!FPeq(p2[j].x, p1[ii].x))
  3771. || (!FPeq(p2[j].y, p1[ii].y)))
  3772. {
  3773. #ifdef GEODEBUG
  3774. printf("plist_same- %d failed reverse match with %dn", j, ii);
  3775. #endif
  3776. break;
  3777. }
  3778. }
  3779. #ifdef GEODEBUG
  3780. printf("plist_same- ii = %d/%d after reverse matchn", ii, npts);
  3781. #endif
  3782. if (ii == npts)
  3783. return TRUE;
  3784. }
  3785. }
  3786. return FALSE;
  3787. } /* plist_same() */