Datum geography_eq(PG_FUNCTION_ARGS) { /* Put aside some stack memory and use it for GIDX pointers. */ char gboxmem1[GIDX_MAX_SIZE]; char gboxmem2[GIDX_MAX_SIZE]; GIDX *gbox1 = (GIDX*)gboxmem1; GIDX *gbox2 = (GIDX*)gboxmem2; POINT3D p1, p2; /* Must be able to build box for each argument (ie, not empty geometry) */ if ( ! gserialized_datum_get_gidx_p(PG_GETARG_DATUM(0), gbox1) || ! gserialized_datum_get_gidx_p(PG_GETARG_DATUM(1), gbox2) ) { PG_RETURN_BOOL(FALSE); } geography_gidx_center(gbox1, &p1); geography_gidx_center(gbox2, &p2); if ( FP_EQUALS(p1.x, p2.x) && FP_EQUALS(p1.y, p2.y) && FP_EQUALS(p1.z, p2.z) ) PG_RETURN_BOOL(TRUE); PG_RETURN_BOOL(FALSE); }
int lwcompound_add_lwgeom(LWCOMPOUND *comp, LWGEOM *geom) { LWCOLLECTION *col = (LWCOLLECTION*)comp; /* Empty things can't continuously join up with other things */ if ( lwgeom_is_empty(geom) ) { LWDEBUG(4, "Got an empty component for a compound curve!"); return LW_FAILURE; } if( col->ngeoms > 0 ) { POINT4D last, first; /* First point of the component we are adding */ LWLINE *newline = (LWLINE*)geom; /* Last point of the previous component */ LWLINE *prevline = (LWLINE*)(col->geoms[col->ngeoms-1]); getPoint4d_p(newline->points, 0, &first); getPoint4d_p(prevline->points, prevline->points->npoints-1, &last); if ( !(FP_EQUALS(first.x,last.x) && FP_EQUALS(first.y,last.y)) ) { LWDEBUG(4, "Components don't join up end-to-end!"); LWDEBUGF(4, "first pt (%g %g %g %g) last pt (%g %g %g %g)", first.x, first.y, first.z, first.m, last.x, last.y, last.z, last.m); return LW_FAILURE; } } col = lwcollection_add_lwgeom(col, geom); return LW_SUCCESS; }
int p2d_same(const POINT2D *p1, const POINT2D *p2) { if( FP_EQUALS(p1->x,p2->x) && FP_EQUALS(p1->y,p2->y) ) return LW_TRUE; else return LW_FALSE; }
int p4d_same(const POINT4D *p1, const POINT4D *p2) { if( FP_EQUALS(p1->x,p2->x) && FP_EQUALS(p1->y,p2->y) && FP_EQUALS(p1->z,p2->z) && FP_EQUALS(p1->m,p2->m) ) return LW_TRUE; else return LW_FALSE; }
/* * Write into the *ret argument coordinates of the closes point on * the given segment to the reference input point. */ void closest_point_on_segment(const POINT4D *p, const POINT4D *A, const POINT4D *B, POINT4D *ret) { double r; if ( FP_EQUALS(A->x, B->x) && FP_EQUALS(A->y, B->y) ) { *ret = *A; return; } /* * We use comp.graphics.algorithms Frequently Asked Questions method * * (1) AC dot AB * r = ---------- * ||AB||^2 * r has the following meaning: * r=0 P = A * r=1 P = B * r<0 P is on the backward extension of AB * r>1 P is on the forward extension of AB * 0<r<1 P is interior to AB * */ r = ( (p->x-A->x) * (B->x-A->x) + (p->y-A->y) * (B->y-A->y) )/( (B->x-A->x)*(B->x-A->x) +(B->y-A->y)*(B->y-A->y) ); if (r<0) { *ret = *A; return; } if (r>1) { *ret = *B; return; } ret->x = A->x + ( (B->x - A->x) * r ); ret->y = A->y + ( (B->y - A->y) * r ); ret->z = A->z + ( (B->z - A->z) * r ); ret->m = A->m + ( (B->m - A->m) * r ); }
static LWMPOINT* lwpoint_locate_along(const LWPOINT *lwpoint, double m, double offset) { double point_m = lwpoint_get_m(lwpoint); LWGEOM *lwg = lwpoint_as_lwgeom(lwpoint); LWMPOINT *r = lwmpoint_construct_empty(lwgeom_get_srid(lwg), lwgeom_has_z(lwg), lwgeom_has_m(lwg)); if ( FP_EQUALS(m, point_m) ) { lwmpoint_add_lwpoint(r, lwpoint_clone(lwpoint)); } return r; }
/** * Create a new leaf node, storing pointers back to the end points for later. */ static CIRC_NODE* circ_node_leaf_new(const POINTARRAY* pa, int i) { POINT2D *p1, *p2; POINT3D q1, q2, c; GEOGRAPHIC_POINT g1, g2, gc; CIRC_NODE *node; double diameter; p1 = (POINT2D*)getPoint_internal(pa, i); p2 = (POINT2D*)getPoint_internal(pa, i+1); geographic_point_init(p1->x, p1->y, &g1); geographic_point_init(p2->x, p2->y, &g2); LWDEBUGF(3,"edge #%d (%g %g, %g %g)", i, p1->x, p1->y, p2->x, p2->y); diameter = sphere_distance(&g1, &g2); /* Zero length edge, doesn't get a node */ if ( FP_EQUALS(diameter, 0.0) ) return NULL; /* Allocate */ node = lwalloc(sizeof(CIRC_NODE)); node->p1 = p1; node->p2 = p2; /* Convert ends to X/Y/Z, sum, and normalize to get mid-point */ geog2cart(&g1, &q1); geog2cart(&g2, &q2); vector_sum(&q1, &q2, &c); normalize(&c); cart2geog(&c, &gc); node->center = gc; node->radius = diameter / 2.0; LWDEBUGF(3,"edge #%d CENTER(%g %g) RADIUS=%g", i, gc.lon, gc.lat, node->radius); /* Leaf has no children */ node->num_nodes = 0; node->nodes = NULL; node->edge_num = i; return node; }
static LWMPOINT* lwmpoint_locate_along(const LWMPOINT *lwin, double m, double offset) { LWGEOM *lwg = lwmpoint_as_lwgeom(lwin); LWMPOINT *lwout = NULL; int i; /* Construct return */ lwout = lwmpoint_construct_empty(lwgeom_get_srid(lwg), lwgeom_has_z(lwg), lwgeom_has_m(lwg)); for ( i = 0; i < lwin->ngeoms; i++ ) { double point_m = lwpoint_get_m(lwin->geoms[i]); if ( FP_EQUALS(m, point_m) ) { lwmpoint_add_lwpoint(lwout, lwpoint_clone(lwin->geoms[i])); } } return lwout; }
LWCOLLECTION* lwgeom_clip_to_ordinate_range(const LWGEOM *lwin, char ordinate, double from, double to, double offset) { LWCOLLECTION *out_col; LWCOLLECTION *out_offset; int i; if ( ! lwin ) lwerror("lwgeom_clip_to_ordinate_range: null input geometry!"); switch ( lwin->type ) { case LINETYPE: out_col = lwline_clip_to_ordinate_range((LWLINE*)lwin, ordinate, from, to); break; case MULTILINETYPE: out_col = lwmline_clip_to_ordinate_range((LWMLINE*)lwin, ordinate, from, to); break; case MULTIPOINTTYPE: out_col = lwmpoint_clip_to_ordinate_range((LWMPOINT*)lwin, ordinate, from, to); break; case POINTTYPE: out_col = lwpoint_clip_to_ordinate_range((LWPOINT*)lwin, ordinate, from, to); break; default: lwerror("This function does not accept %s geometries.", lwtype_name(lwin->type)); return NULL;; } /* Stop if result is NULL */ if ( out_col == NULL ) lwerror("lwgeom_clip_to_ordinate_range clipping routine returned NULL"); /* Return if we aren't going to offset the result */ if ( FP_EQUALS(offset, 0.0) || lwgeom_is_empty(lwcollection_as_lwgeom(out_col)) ) return out_col; /* Construct a collection to hold our outputs. */ /* Things get ugly: GEOS offset drops Z's and M's so we have to drop ours */ out_offset = lwcollection_construct_empty(MULTILINETYPE, lwin->srid, 0, 0); /* Try and offset the linear portions of the return value */ for ( i = 0; i < out_col->ngeoms; i++ ) { int type = out_col->geoms[i]->type; if ( type == POINTTYPE ) { lwnotice("lwgeom_clip_to_ordinate_range cannot offset a clipped point"); continue; } else if ( type == LINETYPE ) { /* lwgeom_offsetcurve(line, offset, quadsegs, joinstyle (round), mitrelimit) */ LWGEOM *lwoff = lwgeom_offsetcurve(lwgeom_as_lwline(out_col->geoms[i]), offset, 8, 1, 5.0); if ( ! lwoff ) { lwerror("lwgeom_offsetcurve returned null"); } lwcollection_add_lwgeom(out_offset, lwoff); } else { lwerror("lwgeom_clip_to_ordinate_range found an unexpected type (%s) in the offset routine",lwtype_name(type)); } } return out_offset; }
int ptarrayarc_contains_point_partial(const POINTARRAY *pa, const POINT2D *pt, int check_closed, int *winding_number) { int wn = 0; int i, side; const POINT2D *seg1; const POINT2D *seg2; const POINT2D *seg3; GBOX gbox; /* Check for not an arc ring (always have odd # of points) */ if ( (pa->npoints % 2) == 0 ) { lwerror("ptarrayarc_contains_point called with even number of points"); return LW_OUTSIDE; } /* Check for not an arc ring (always have >= 3 points) */ if ( pa->npoints < 3 ) { lwerror("ptarrayarc_contains_point called too-short pointarray"); return LW_OUTSIDE; } /* Check for unclosed case */ seg1 = getPoint2d_cp(pa, 0); seg3 = getPoint2d_cp(pa, pa->npoints-1); if ( check_closed && ! p2d_same(seg1, seg3) ) { lwerror("ptarrayarc_contains_point called on unclosed ring"); return LW_OUTSIDE; } /* OK, it's closed. Is it just one circle? */ else if ( p2d_same(seg1, seg3) && pa->npoints == 3 ) { double radius, d; POINT2D c; seg2 = getPoint2d_cp(pa, 1); /* Wait, it's just a point, so it can't contain anything */ if ( lw_arc_is_pt(seg1, seg2, seg3) ) return LW_OUTSIDE; /* See if the point is within the circle radius */ radius = lw_arc_center(seg1, seg2, seg3, &c); d = distance2d_pt_pt(pt, &c); if ( FP_EQUALS(d, radius) ) return LW_BOUNDARY; /* Boundary of circle */ else if ( d < radius ) return LW_INSIDE; /* Inside circle */ else return LW_OUTSIDE; /* Outside circle */ } else if ( p2d_same(seg1, pt) || p2d_same(seg3, pt) ) { return LW_BOUNDARY; /* Boundary case */ } /* Start on the ring */ seg1 = getPoint2d_cp(pa, 0); for ( i=1; i < pa->npoints; i += 2 ) { seg2 = getPoint2d_cp(pa, i); seg3 = getPoint2d_cp(pa, i+1); /* Catch an easy boundary case */ if( p2d_same(seg3, pt) ) return LW_BOUNDARY; /* Skip arcs that have no size */ if ( lw_arc_is_pt(seg1, seg2, seg3) ) { seg1 = seg3; continue; } /* Only test segments in our vertical range */ lw_arc_calculate_gbox_cartesian_2d(seg1, seg2, seg3, &gbox); if ( pt->y > gbox.ymax || pt->y < gbox.ymin ) { seg1 = seg3; continue; } /* Outside of horizontal range, and not between end points we also skip */ if ( (pt->x > gbox.xmax || pt->x < gbox.xmin) && (pt->y > FP_MAX(seg1->y, seg3->y) || pt->y < FP_MIN(seg1->y, seg3->y)) ) { seg1 = seg3; continue; } side = lw_arc_side(seg1, seg2, seg3, pt); /* On the boundary */ if ( (side == 0) && lw_pt_in_arc(pt, seg1, seg2, seg3) ) { return LW_BOUNDARY; } /* Going "up"! Point to left of arc. */ if ( side < 0 && (seg1->y <= pt->y) && (pt->y < seg3->y) ) { wn++; } /* Going "down"! */ if ( side > 0 && (seg2->y <= pt->y) && (pt->y < seg1->y) ) { wn--; } /* Inside the arc! */ if ( pt->x <= gbox.xmax && pt->x >= gbox.xmin ) { POINT2D C; double radius = lw_arc_center(seg1, seg2, seg3, &C); double d = distance2d_pt_pt(pt, &C); /* On the boundary! */ if ( d == radius ) return LW_BOUNDARY; /* Within the arc! */ if ( d < radius ) { /* Left side, increment winding number */ if ( side < 0 ) wn++; /* Right side, decrement winding number */ if ( side > 0 ) wn--; } } seg1 = seg3; } /* Sent out the winding number for calls that are building on this as a primitive */ if ( winding_number ) *winding_number = wn; /* Outside */ if (wn == 0) { return LW_OUTSIDE; } /* Inside */ return LW_INSIDE; }
/** * Create a new internal node, calculating the new measure range for the node, * and storing pointers to the child nodes. */ static CIRC_NODE* circ_node_internal_new(CIRC_NODE** c, int num_nodes) { CIRC_NODE *node = NULL; GEOGRAPHIC_POINT new_center, c1; double new_radius; double offset1, dist, D, r1, ri; int i; LWDEBUGF(3, "called with %d nodes --", num_nodes); /* Can't do anything w/ empty input */ if ( num_nodes < 1 ) return node; /* Initialize calculation with values of the first circle */ new_center = c[0]->center; new_radius = c[0]->radius; /* Merge each remaining circle into the new circle */ for ( i = 1; i < num_nodes; i++ ) { c1 = new_center; r1 = new_radius; dist = sphere_distance(&c1, &(c[i]->center)); ri = c[i]->radius; LWDEBUGF(3, "distance between new (%g %g) and %i (%g %g) is %g", c1.lon, c1.lat, i, c[i]->center.lon, c[i]->center.lat, dist); if ( FP_EQUALS(dist, 0) ) { LWDEBUG(3, " distance between centers is zero"); new_radius = r1 + 2*dist; new_center = c1; } else if ( dist < fabs(r1 - ri) ) { /* new contains next */ if ( r1 > ri ) { LWDEBUG(3, " c1 contains ci"); new_center = c1; new_radius = r1; } /* next contains new */ else { LWDEBUG(3, " ci contains c1"); new_center = c[i]->center; new_radius = ri; } } else { LWDEBUG(3, " calculating new center"); /* New circle diameter */ D = dist + r1 + ri; LWDEBUGF(3," D is %g", D); /* New radius */ new_radius = D / 2.0; /* Distance from cn1 center to the new center */ offset1 = ri + (D - (2.0*r1 + 2.0*ri)) / 2.0; LWDEBUGF(3," offset1 is %g", offset1); /* Sometimes the sphere_direction function fails... this causes the center calculation */ /* to fail too. In that case, we're going to fall back ot a cartesian calculation, which */ /* is less exact, so we also have to pad the radius by (hack alert) an arbitrary amount */ /* which is hopefully always big enough to contain the input edges */ if ( circ_center_spherical(&c1, &(c[i]->center), dist, offset1, &new_center) == LW_FAILURE ) { circ_center_cartesian(&c1, &(c[i]->center), dist, offset1, &new_center); new_radius *= 1.1; } } LWDEBUGF(3, " new center is (%g %g) new radius is %g", new_center.lon, new_center.lat, new_radius); } node = lwalloc(sizeof(CIRC_NODE)); node->p1 = NULL; node->p2 = NULL; node->center = new_center; node->radius = new_radius; node->num_nodes = num_nodes; node->nodes = c; node->edge_num = -1; return node; }