Пример #1
0
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;
}
Пример #2
0
/*
 * 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;
}
Пример #3
0
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 */
}