static VALUE method_geometry_distance(VALUE self, VALUE rhs) { VALUE result = Qnil; RGeo_GeometryData* self_data = RGEO_GEOMETRY_DATA_PTR(self); const GEOSGeometry* self_geom = self_data->geom; if (self_geom) { const GEOSGeometry* rhs_geom = rgeo_convert_to_geos_geometry(self_data->factory, rhs, Qnil); if (rhs_geom) { double dist; if (GEOSDistance_r(self_data->geos_context, self_geom, rhs_geom, &dist)) { result = rb_float_new(dist); } } } return result; }
/* * Return whether the given line segment is suitable as an * approximation of the projection of the source line. * * t_start: Interpolation parameter for the start point. * p_start: Projected start point. * t_end: Interpolation parameter for the end point. * p_start: Projected end point. * interpolator: Interpolator for current source line. * threshold: Lateral tolerance in target projection coordinates. * handle: Thread-local context handle for GEOS. * gp_domain: Prepared polygon of target map domain. * inside: Whether the start point is within the map domain. */ bool straightAndDomain(double t_start, const Point &p_start, double t_end, const Point &p_end, Interpolator *interpolator, double threshold, GEOSContextHandle_t handle, const GEOSPreparedGeometry *gp_domain, bool inside) { // Straight and in-domain (de9im[7] == 'F') bool valid; // This could be optimised out of the loop. if (!(isfinite(p_start.x) && isfinite(p_start.y))) { valid = false; } else if (!(isfinite(p_end.x) && isfinite(p_end.y))) { valid = false; } else { // TODO: Re-use geometries, instead of create-destroy! // Create a LineString for the current end-point. GEOSCoordSequence *coords = GEOSCoordSeq_create_r(handle, 2, 2); GEOSCoordSeq_setX_r(handle, coords, 0, p_start.x); GEOSCoordSeq_setY_r(handle, coords, 0, p_start.y); GEOSCoordSeq_setX_r(handle, coords, 1, p_end.x); GEOSCoordSeq_setY_r(handle, coords, 1, p_end.y); GEOSGeometry *g_segment = GEOSGeom_createLineString_r(handle, coords); // Find the projected mid-point double t_mid = (t_start + t_end) * 0.5; Point p_mid = interpolator->interpolate(t_mid); // Make it into a GEOS geometry coords = GEOSCoordSeq_create_r(handle, 1, 2); GEOSCoordSeq_setX_r(handle, coords, 0, p_mid.x); GEOSCoordSeq_setY_r(handle, coords, 0, p_mid.y); GEOSGeometry *g_mid = GEOSGeom_createPoint_r(handle, coords); double along = GEOSProjectNormalized_r(handle, g_segment, g_mid); if(isnan(along)) { valid = true; } else { valid = 0.0 < along && along < 1.0; if (valid) { double separation; GEOSDistance_r(handle, g_segment, g_mid, &separation); if (inside) { // Scale the lateral threshold by the distance from // the nearest end. I.e. Near the ends the lateral // threshold is much smaller; it only has its full // value in the middle. valid = separation <= threshold * 2.0 * (0.5 - fabs(0.5 - along)); } else { // Check if the mid-point makes less than ~11 degree // angle with the straight line. // sin(11') => 0.2 // To save the square-root we just use the square of // the lengths, hence: // 0.2 ^ 2 => 0.04 double hypot_dx = p_mid.x - p_start.x; double hypot_dy = p_mid.y - p_start.y; double hypot = hypot_dx * hypot_dx + hypot_dy * hypot_dy; valid = ((separation * separation) / hypot) < 0.04; } } } if (valid) { if(inside) valid = GEOSPreparedCovers_r(handle, gp_domain, g_segment); else valid = GEOSPreparedDisjoint_r(handle, gp_domain, g_segment); } GEOSGeom_destroy_r(handle, g_segment); GEOSGeom_destroy_r(handle, g_mid); } return valid; }
static CPLErr BlendMaskGenerator( #ifndef HAVE_GEOS CPL_UNUSED int nXOff, CPL_UNUSED int nYOff, CPL_UNUSED int nXSize, CPL_UNUSED int nYSize, CPL_UNUSED GByte *pabyPolyMask, CPL_UNUSED float *pafValidityMask, CPL_UNUSED OGRGeometryH hPolygon, CPL_UNUSED double dfBlendDist #else int nXOff, int nYOff, int nXSize, int nYSize, GByte *pabyPolyMask, float *pafValidityMask, OGRGeometryH hPolygon, double dfBlendDist #endif ) { #ifndef HAVE_GEOS CPLError( CE_Failure, CPLE_AppDefined, "Blend distance support not available without the GEOS library."); return CE_Failure; #else /* HAVE_GEOS */ /* -------------------------------------------------------------------- */ /* Convert the polygon into a collection of lines so that we */ /* measure distance from the edge even on the inside. */ /* -------------------------------------------------------------------- */ OGRGeometry *poLines = OGRGeometryFactory::forceToMultiLineString( ((OGRGeometry *) hPolygon)->clone() ); /* -------------------------------------------------------------------- */ /* Prepare a clipping polygon a bit bigger than the area of */ /* interest in the hopes of simplifying the cutline down to */ /* stuff that will be relavent for this area of interest. */ /* -------------------------------------------------------------------- */ CPLString osClipRectWKT; osClipRectWKT.Printf( "POLYGON((%g %g,%g %g,%g %g,%g %g,%g %g))", nXOff - (dfBlendDist+1), nYOff - (dfBlendDist+1), nXOff + nXSize + (dfBlendDist+1), nYOff - (dfBlendDist+1), nXOff + nXSize + (dfBlendDist+1), nYOff + nYSize + (dfBlendDist+1), nXOff - (dfBlendDist+1), nYOff + nYSize + (dfBlendDist+1), nXOff - (dfBlendDist+1), nYOff - (dfBlendDist+1) ); OGRPolygon *poClipRect = NULL; char *pszWKT = (char *) osClipRectWKT.c_str(); OGRGeometryFactory::createFromWkt( &pszWKT, NULL, (OGRGeometry**) (&poClipRect) ); if( poClipRect ) { /***** if it doesnt intersect the polym zero the mask and return *****/ if ( ! ((OGRGeometry *) hPolygon)->Intersects( poClipRect ) ) { memset( pafValidityMask, 0, sizeof(float) * nXSize * nYSize ); delete poLines; delete poClipRect; return CE_None; } /***** if it doesnt intersect the line at all just return *****/ else if ( ! ((OGRGeometry *) poLines)->Intersects( poClipRect ) ) { delete poLines; delete poClipRect; return CE_None; } OGRGeometry *poClippedLines = poLines->Intersection( poClipRect ); delete poLines; poLines = poClippedLines; delete poClipRect; } /* -------------------------------------------------------------------- */ /* Convert our polygon into GEOS format, and compute an */ /* envelope to accelerate later distance operations. */ /* -------------------------------------------------------------------- */ OGREnvelope sEnvelope; int iXMin, iYMin, iXMax, iYMax; GEOSContextHandle_t hGEOSCtxt = OGRGeometry::createGEOSContext(); GEOSGeom poGEOSPoly; poGEOSPoly = poLines->exportToGEOS(hGEOSCtxt); OGR_G_GetEnvelope( hPolygon, &sEnvelope ); delete poLines; /***** this check was already done in the calling *****/ /***** function and should never be true *****/ /*if( sEnvelope.MinY - dfBlendDist > nYOff+nYSize || sEnvelope.MaxY + dfBlendDist < nYOff || sEnvelope.MinX - dfBlendDist > nXOff+nXSize || sEnvelope.MaxX + dfBlendDist < nXOff ) return CE_None; */ iXMin = MAX(0,(int) floor(sEnvelope.MinX - dfBlendDist - nXOff)); iXMax = MIN(nXSize, (int) ceil(sEnvelope.MaxX + dfBlendDist - nXOff)); iYMin = MAX(0,(int) floor(sEnvelope.MinY - dfBlendDist - nYOff)); iYMax = MIN(nYSize, (int) ceil(sEnvelope.MaxY + dfBlendDist - nYOff)); /* -------------------------------------------------------------------- */ /* Loop over potential area within blend line distance, */ /* processing each pixel. */ /* -------------------------------------------------------------------- */ int iY, iX; double dfLastDist; for( iY = 0; iY < nYSize; iY++ ) { dfLastDist = 0.0; for( iX = 0; iX < nXSize; iX++ ) { if( iX < iXMin || iX >= iXMax || iY < iYMin || iY > iYMax || dfLastDist > dfBlendDist + 1.5 ) { if( pabyPolyMask[iX + iY * nXSize] == 0 ) pafValidityMask[iX + iY * nXSize] = 0.0; dfLastDist -= 1.0; continue; } double dfDist, dfRatio; CPLString osPointWKT; GEOSGeom poGEOSPoint; osPointWKT.Printf( "POINT(%d.5 %d.5)", iX + nXOff, iY + nYOff ); poGEOSPoint = GEOSGeomFromWKT_r( hGEOSCtxt, osPointWKT ); GEOSDistance_r( hGEOSCtxt, poGEOSPoly, poGEOSPoint, &dfDist ); GEOSGeom_destroy_r( hGEOSCtxt, poGEOSPoint ); dfLastDist = dfDist; if( dfDist > dfBlendDist ) { if( pabyPolyMask[iX + iY * nXSize] == 0 ) pafValidityMask[iX + iY * nXSize] = 0.0; continue; } if( pabyPolyMask[iX + iY * nXSize] == 0 ) { /* outside */ dfRatio = 0.5 - (dfDist / dfBlendDist) * 0.5; } else { /* inside */ dfRatio = 0.5 + (dfDist / dfBlendDist) * 0.5; } pafValidityMask[iX + iY * nXSize] *= (float)dfRatio; } } /* -------------------------------------------------------------------- */ /* Cleanup */ /* -------------------------------------------------------------------- */ GEOSGeom_destroy_r( hGEOSCtxt, poGEOSPoly ); OGRGeometry::freeGEOSContext( hGEOSCtxt ); return CE_None; #endif /* HAVE_GEOS */ }