Skip to content

Commit

Permalink
Support reference with one measure (along)
Browse files Browse the repository at this point in the history
  • Loading branch information
mhugent committed Feb 1, 2012
1 parent fb73d0f commit 2bf6af1
Show file tree
Hide file tree
Showing 2 changed files with 308 additions and 14 deletions.
310 changes: 298 additions & 12 deletions src/analysis/vector/qgsgeometryanalyzer.cpp
Expand Up @@ -991,20 +991,306 @@ bool QgsGeometryAnalyzer::eventLayer( QgsVectorLayer* lineLayer, QgsVectorLayer*
return true;
}

QgsGeometry* QgsGeometryAnalyzer::locateAlongMeasure( double measure, const QgsGeometry* lineGeom )
QgsGeometry* QgsGeometryAnalyzer::locateBetweenMeasures( double fromMeasure, double toMeasure, QgsGeometry* lineGeom )
{
//only for testing
QgsGeometry* geom = new QgsGeometry();
*geom = *lineGeom;
geom->convertToMultiType();
return geom;
if ( !lineGeom )
{
return 0;
}

QgsMultiPolyline resultGeom;

//need to go with WKB and z coordinate until QgsGeometry supports M values
unsigned char* lineWkb = lineGeom->asWkb();
int wkbSize = lineGeom->wkbSize();

unsigned char* ptr = lineWkb + 1;
QGis::WkbType wkbType;
memcpy( &wkbType, ptr, sizeof( wkbType ) );
ptr += sizeof( wkbType );

if ( wkbType != QGis::WKBLineString25D && wkbType != QGis::WKBMultiLineString25D )
{
return 0;
}

if ( wkbType == QGis::WKBLineString25D )
{
locateBetweenWkbString( ptr, resultGeom, fromMeasure, toMeasure );
}
else if ( wkbType == QGis::WKBMultiLineString25D )
{
int* nLines = ( int* )ptr;
ptr += sizeof( int );
for ( int i = 0; i < *nLines; ++i )
{
ptr += ( 1 + sizeof( wkbType ) );
ptr = locateBetweenWkbString( ptr, resultGeom, fromMeasure, toMeasure );
}
}

return QgsGeometry::fromMultiPolyline( resultGeom );
}

QgsGeometry* QgsGeometryAnalyzer::locateAlongMeasure( double measure, QgsGeometry* lineGeom )
{
if ( !lineGeom )
{
return 0;
}

QgsMultiPoint resultGeom;

//need to go with WKB and z coordinate until QgsGeometry supports M values
unsigned char* lineWkb = lineGeom->asWkb();

unsigned char* ptr = lineWkb + 1;
QGis::WkbType wkbType;
memcpy( &wkbType, ptr, sizeof( wkbType ) );
ptr += sizeof( wkbType );

if ( wkbType != QGis::WKBLineString25D && wkbType != QGis::WKBMultiLineString25D )
{
return 0;
}

if ( wkbType == QGis::WKBLineString25D )
{
locateAlongWkbString( ptr, resultGeom, measure );
}
else if ( wkbType == QGis::WKBMultiLineString25D )
{
int* nLines = ( int* )ptr;
ptr += sizeof( int );
for ( int i = 0; i < *nLines; ++i )
{
ptr += ( 1 + sizeof( wkbType ) );
ptr = locateAlongWkbString( ptr, resultGeom, measure );
}
}

return QgsGeometry::fromMultiPoint( resultGeom );
}

unsigned char* QgsGeometryAnalyzer::locateBetweenWkbString( unsigned char* ptr, QgsMultiPolyline& result, double fromMeasure, double toMeasure )
{
int* nPoints = ( int* ) ptr;
ptr += sizeof( int );
double prevx, prevy, prevz;
double *x, *y, *z;
QgsPolyline currentLine;

QgsPoint pt1, pt2;
bool measureInSegment; //true if measure is contained in the segment
bool secondPointClipped; //true if second point is != segment endpoint


for ( int i = 0; i < *nPoints; ++i )
{
x = ( double* )ptr;
ptr += sizeof( double );
y = ( double* )ptr;
ptr += sizeof( double );
z = ( double* ) ptr;
ptr += sizeof( double );

if ( i > 0 )
{
measureInSegment = clipSegmentByRange( prevx, prevy, prevz, *x, *y, *z, fromMeasure, toMeasure, pt1, pt2, secondPointClipped );
if ( measureInSegment )
{
if ( currentLine.size() < 1 ) //no points collected yet, so the first point needs to be added to the line
{
currentLine.append( pt1 );
}
currentLine.append( pt2 );
if ( secondPointClipped || i == *nPoints - 1 ) //close current segment
{
result.append( currentLine );
currentLine.clear();
}
}
}
prevx = *x; prevy = *y; prevz = *z;
}
return ptr;
}

unsigned char* QgsGeometryAnalyzer::locateAlongWkbString( unsigned char* ptr, QgsMultiPoint& result, double measure )
{
int* nPoints = ( int* ) ptr;
ptr += sizeof( int );
double prevx, prevy, prevz;
double *x, *y, *z;

QgsPoint pt1, pt2;
bool pt1Ok, pt2Ok;

for ( int i = 0; i < *nPoints; ++i )
{
x = ( double* )ptr;
ptr += sizeof( double );
y = ( double* )ptr;
ptr += sizeof( double );
z = ( double* ) ptr;
ptr += sizeof( double );

if ( i > 0 )
{
locateAlongSegment( prevx, prevy, prevz, *x, *y, *z, measure, pt1Ok, pt1, pt2Ok, pt2 );
if ( pt1Ok )
{
result.append( pt1 );
}
if ( pt2Ok && ( i == ( *nPoints - 1 ) ) )
{
result.append( pt2 );
}
}
prevx = *x; prevy = *y; prevz = *z;
}
return ptr;
}

bool QgsGeometryAnalyzer::clipSegmentByRange( double x1, double y1, double m1, double x2, double y2, double m2, double range1, double range2, QgsPoint& pt1,
QgsPoint& pt2, bool& secondPointClipped )
{
bool reversed = m1 > m2;
double tmp;

//reverse m1, m2 if necessary
if ( reversed )
{
tmp = m1;
m1 = m2;
m2 = tmp;
}

//reverse range1, range2 if necessary
if ( range1 > range2 )
{
tmp = range1;
range1 = range2;
range2 = tmp;
}

//segment completely outside of range
if ( m2 < range1 || m1 > range2 )
{
return false;
}

//segment completely inside of range
if ( m2 <= range2 && m1 >= range1 )
{
pt1.setX( x1 ); pt1.setY( y1 );
pt2.setX( x2 ); pt2.setY( y2 );
secondPointClipped = false;
}

//m1 inside and m2 not
if ( m1 >= range1 && m1 <= range2 )
{
pt1.setX( x1 ); pt1.setY( y1 );
double dist = ( range2 - m1 ) / ( m2 - m1 );
pt2.setX( x1 + ( x2 - x1 ) * dist );
pt2.setY( y1 + ( y2 - y1 ) * dist );
secondPointClipped = !reversed;
}

//m2 inside and m1 not
if ( m2 >= range1 && m2 <= range2 )
{
pt2.setX( x2 ); pt2.setY( y2 );
double dist = ( m2 - range1 ) / ( m2 - m1 );
pt1.setX( x2 - ( x2 - x1 ) * dist );
pt1.setY( y2 - ( y2 - y1 ) * dist );
secondPointClipped = reversed;
}

if ( reversed ) //switch p1 and p2
{
QgsPoint tmpPt = pt1;
pt1 = pt2;
pt2 = tmpPt;
}

return true;
}

QgsGeometry* QgsGeometryAnalyzer::locateBetweenMeasures( double fromMeasure, double toMeasure, const QgsGeometry* lineGeom )
void QgsGeometryAnalyzer::locateAlongSegment( double x1, double y1, double m1, double x2, double y2, double m2, double measure, bool& pt1Ok, QgsPoint& pt1, bool& pt2Ok, QgsPoint& pt2 )
{
//only for testing
QgsGeometry* geom = new QgsGeometry();
*geom = *lineGeom;
geom->convertToMultiType();
return geom;
bool reversed = false;
pt1Ok = false;
pt2Ok = false;

if ( m1 > m2 )
{
double tmp = m1;
m1 = m2;
m2 = tmp;
reversed = true;
}

//segment does not match
if ( measure < m1 || measure > m2 )
{
pt1Ok = false;
pt2Ok = false;
return;
}

//match with vertex1
if ( doubleNear( m1, measure ) )
{
if ( reversed )
{
pt2Ok = true;
pt2.setX( x2 ); pt2.setY( y2 );
}
else
{
pt1Ok = true;
pt1.setX( x1 ); pt1.setY( y1 );
}
}

//match with vertex2
if ( doubleNear( m2, measure ) )
{
if ( reversed )
{
pt1Ok = true;
pt1.setX( x1 ); pt1.setY( y1 );
}
else
{
pt2Ok = true;
pt2.setX( x2 ); pt2.setY( y2 );
}
}


if ( pt1Ok || pt2Ok )
{
return;
}

//match between the vertices
if ( doubleNear( m1, m2 ) )
{
pt1.setX( x1 );
pt1.setY( y1 );
pt1Ok = true;
return;
}
double dist = ( measure - m1 ) / ( m2 - m1 );
if ( reversed )
{
dist = 1 - dist;
}

pt1.setX( x1 + dist * ( x2 - x1 ) );
pt1.setY( y1 + dist * ( y2 - y1 ) );
pt1Ok = true;
}
12 changes: 10 additions & 2 deletions src/analysis/vector/qgsgeometryanalyzer.h
Expand Up @@ -126,8 +126,16 @@ class ANALYSIS_EXPORT QgsGeometryAnalyzer
void convexFeature( QgsFeature& f, int nProcessedFeatures, QgsGeometry** dissolveGeometry );
/**Helper function to dissolve feature(s)*/
void dissolveFeature( QgsFeature& f, int nProcessedFeatures, QgsGeometry** dissolveGeometry );
QgsGeometry* locateAlongMeasure( double measure, const QgsGeometry* lineGeom );
QgsGeometry* locateBetweenMeasures( double fromMeasure, double toMeasure, const QgsGeometry* lineGeom );

//helper functions for event layer

/**Returns multilinestring*/
QgsGeometry* locateBetweenMeasures( double fromMeasure, double toMeasure, QgsGeometry* lineGeom );
/**Returns multipoint*/
QgsGeometry* locateAlongMeasure( double measure, QgsGeometry* lineGeom );
unsigned char* locateBetweenWkbString( unsigned char* ptr, QgsMultiPolyline& result, double fromMeasure, double toMeasure );
unsigned char* locateAlongWkbString( unsigned char* ptr, QgsMultiPoint& result, double measure );
static bool clipSegmentByRange( double x1, double y1, double m1, double x2, double y2, double m2, double range1, double range2, QgsPoint& pt1, QgsPoint& pt2, bool& secondPointClipped );
static void locateAlongSegment( double x1, double y1, double m1, double x2, double y2, double m2, double measure, bool& pt1Ok, QgsPoint& pt1, bool& pt2Ok, QgsPoint& pt2 );
};
#endif //QGSVECTORANALYZER

0 comments on commit 2bf6af1

Please sign in to comment.