Ticket #390: addmeasure.patch

File addmeasure.patch, 3.4 KB (added by pramsey, 2 years ago)

ST_AddMeasure implementation

  • liblwgeom/lwline.c

     
    524524{ 
    525525        setPoint4d(line->points, index, newpoint); 
    526526} 
     527 
     528/** 
     529* Re-write the measure ordinate (or add one, if it isn't already there) interpolating 
     530* the measure between the supplied start and end values.  
     531*/ 
     532LWLINE*  
     533lwline_measured_from_lwline(const LWLINE *lwline, double m_start, double m_end) 
     534{ 
     535        int i = 0; 
     536        int hasm = 0, hasz = 0; 
     537        int npoints = 0; 
     538        double length = 0.0; 
     539        double length_so_far = 0.0; 
     540        double m_range = m_end - m_start; 
     541        double m; 
     542        POINTARRAY *pa = NULL; 
     543        POINT3DZ p1, p2; 
     544         
     545        if( TYPE_GETTYPE(lwline->type) != LINETYPE ) 
     546        { 
     547                lwerror("lwmline_construct_from_lwline: only line types supported"); 
     548                return NULL; 
     549        } 
     550         
     551        hasz = TYPE_HASZ(lwline->type); 
     552        hasm = 1; 
     553         
     554        /* Null points or npoints == 0 will result in empty return geometry */ 
     555        if( lwline->points ) 
     556        { 
     557                npoints = lwline->points->npoints; 
     558                length = lwgeom_pointarray_length2d(lwline->points); 
     559                getPoint3dz_p(lwline->points, 0, &p1); 
     560        } 
     561         
     562        pa = ptarray_construct(hasz, hasm, npoints); 
     563         
     564        for( i = 0; i < npoints; i++ ) 
     565        {                
     566                POINT4D q; 
     567                getPoint3dz_p(lwline->points, i, &p2); 
     568                length_so_far += distance2d_pt_pt((POINT2D*)&p1, (POINT2D*)&p2); 
     569                if ( length > 0.0 ) 
     570                        m = m_start + m_range * length_so_far / length; 
     571                else 
     572                        m = 0.0; 
     573                q.x = p2.x; 
     574                q.y = p2.y; 
     575                q.z = p2.z; 
     576                q.m = m; 
     577                setPoint4d(pa, i, &q); 
     578                p1 = p2; 
     579        } 
     580         
     581        return lwline_construct(lwline->SRID, NULL, pa); 
     582} 
  • liblwgeom/liblwgeom.h

     
    13791379extern POINTARRAY *ptarray_substring(POINTARRAY *, double, double); 
    13801380extern double ptarray_locate_point(POINTARRAY *, POINT2D *); 
    13811381extern void closest_point_on_segment(POINT2D *p, POINT2D *A, POINT2D *B, POINT2D *ret); 
     1382extern LWLINE *lwline_measured_from_lwline(const LWLINE *lwline, double m_start, double m_end); 
    13821383 
    13831384/* 
    13841385 * Ensure every segment is at most 'dist' long. 
  • postgis/lwgeom_functions_lrs.c

     
    1818 
    1919 
    2020Datum LWGEOM_locate_between_m(PG_FUNCTION_ARGS); 
     21Datum ST_AddMeasure(PG_FUNCTION_ARGS); 
    2122 
    2223typedef struct 
    2324{ 
     
    535536        PG_RETURN_POINTER(gout); 
    536537} 
    537538 
     539 
     540/* 
     541* CREATE OR REPLACE FUNCTION ST_AddMeasure(geometry, float8, float8)  
     542* RETURNS geometry  
     543* AS '$libdir/postgis-1.5', 'ST_AddMeasure'  
     544* LANGUAGE 'C' IMMUTABLE STRICT; 
     545*/ 
     546PG_FUNCTION_INFO_V1(ST_AddMeasure); 
     547Datum ST_AddMeasure(PG_FUNCTION_ARGS) 
     548{ 
     549        PG_LWGEOM *gin = (PG_LWGEOM *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); 
     550        PG_LWGEOM *gout; 
     551        double start_measure = PG_GETARG_FLOAT8(1); 
     552        double end_measure = PG_GETARG_FLOAT8(2); 
     553        LWGEOM *lwin, *lwout; 
     554 
     555        /* Raise an error if input is not a linestring */ 
     556        if ( TYPE_GETTYPE(gin->type) != LINETYPE ) 
     557        { 
     558                lwerror("Only LINESTRING is supported"); 
     559                PG_RETURN_NULL(); 
     560        } 
     561 
     562        lwin = pglwgeom_deserialize(gin); 
     563        lwout = (LWGEOM*)lwline_measured_from_lwline((LWLINE*)lwin, start_measure, end_measure); 
     564        lwgeom_release(lwin); 
     565 
     566        if ( lwout == NULL ) 
     567                PG_RETURN_NULL(); 
     568 
     569        gout = pglwgeom_serialize(lwout); 
     570        lwgeom_release(lwout); 
     571 
     572        PG_RETURN_POINTER(gout); 
     573} 
     574