mirror of
https://github.com/qgis/QGIS.git
synced 2025-04-14 00:07:35 -04:00
Add method to QgsGeometry to extend the start/end of a linestring
This commit is contained in:
parent
c494c472ac
commit
ef34e393dc
@ -514,6 +514,14 @@ class QgsGeometry
|
||||
JoinStyle joinStyle = JoinStyleRound,
|
||||
double mitreLimit = 2.0 ) const;
|
||||
|
||||
/**
|
||||
* Extends a (multi)line geometry by extrapolating out the start or end of the line
|
||||
* by a specified distance. Lines are extended using the bearing of the first or last
|
||||
* segment in the line.
|
||||
* @note added in QGIS 3.0
|
||||
*/
|
||||
QgsGeometry extendLine( double startDistance, double endDistance ) const;
|
||||
|
||||
/** Returns a simplified version of this geometry using a specified tolerance value */
|
||||
QgsGeometry simplify( double tolerance ) const;
|
||||
|
||||
|
@ -92,6 +92,14 @@ class QgsLineString: public QgsCurve
|
||||
@return the converted geometry. Caller takes ownership*/
|
||||
QgsAbstractGeometry* toCurveType() const /Factory/;
|
||||
|
||||
/**
|
||||
* Extends the line geometry by extrapolating out the start or end of the line
|
||||
* by a specified distance. Lines are extended using the bearing of the first or last
|
||||
* segment in the line.
|
||||
* @note added in QGIS 3.0
|
||||
*/
|
||||
void extend( double startDistance, double endDistance );
|
||||
|
||||
//reimplemented methods
|
||||
|
||||
virtual QString geometryType() const;
|
||||
|
@ -1452,6 +1452,45 @@ QgsGeometry QgsGeometry::singleSidedBuffer( double distance, int segments, Buffe
|
||||
}
|
||||
}
|
||||
|
||||
QgsGeometry QgsGeometry::extendLine( double startDistance, double endDistance ) const
|
||||
{
|
||||
if ( !d->geometry || type() != QgsWkbTypes::LineGeometry )
|
||||
{
|
||||
return QgsGeometry();
|
||||
}
|
||||
|
||||
if ( QgsWkbTypes::isMultiType( d->geometry->wkbType() ) )
|
||||
{
|
||||
QList<QgsGeometry> parts = asGeometryCollection();
|
||||
QList<QgsGeometry> results;
|
||||
Q_FOREACH ( const QgsGeometry& part, parts )
|
||||
{
|
||||
QgsGeometry result = part.extendLine( startDistance, endDistance );
|
||||
if ( result )
|
||||
results << result;
|
||||
}
|
||||
if ( results.isEmpty() )
|
||||
return QgsGeometry();
|
||||
|
||||
QgsGeometry first = results.takeAt( 0 );
|
||||
Q_FOREACH ( const QgsGeometry& result, results )
|
||||
{
|
||||
first.addPart( & result );
|
||||
}
|
||||
return first;
|
||||
}
|
||||
else
|
||||
{
|
||||
QgsLineString* line = dynamic_cast< QgsLineString* >( d->geometry );
|
||||
if ( !line )
|
||||
return QgsGeometry();
|
||||
|
||||
QgsLineString* newLine = line->clone();
|
||||
newLine->extend( startDistance, endDistance );
|
||||
return QgsGeometry( newLine );
|
||||
}
|
||||
}
|
||||
|
||||
QgsGeometry QgsGeometry::simplify( double tolerance ) const
|
||||
{
|
||||
if ( !d->geometry )
|
||||
|
@ -558,6 +558,14 @@ class CORE_EXPORT QgsGeometry
|
||||
JoinStyle joinStyle = JoinStyleRound,
|
||||
double mitreLimit = 2.0 ) const;
|
||||
|
||||
/**
|
||||
* Extends a (multi)line geometry by extrapolating out the start or end of the line
|
||||
* by a specified distance. Lines are extended using the bearing of the first or last
|
||||
* segment in the line.
|
||||
* @note added in QGIS 3.0
|
||||
*/
|
||||
QgsGeometry extendLine( double startDistance, double endDistance ) const;
|
||||
|
||||
//! Returns a simplified version of this geometry using a specified tolerance value
|
||||
QgsGeometry simplify( double tolerance ) const;
|
||||
|
||||
|
@ -583,6 +583,32 @@ QgsAbstractGeometry* QgsLineString::toCurveType() const
|
||||
return compoundCurve;
|
||||
}
|
||||
|
||||
void QgsLineString::extend( double startDistance, double endDistance )
|
||||
{
|
||||
if ( mX.size() < 2 || mY.size() < 2 )
|
||||
return;
|
||||
|
||||
// start of line
|
||||
if ( startDistance > 0 )
|
||||
{
|
||||
double currentLen = sqrt( qPow( mX.at( 0 ) - mX.at( 1 ), 2 ) +
|
||||
qPow( mY.at( 0 ) - mY.at( 1 ), 2 ) );
|
||||
double newLen = currentLen + startDistance;
|
||||
mX[ 0 ] = mX.at( 1 ) + ( mX.at( 0 ) - mX.at( 1 ) ) / currentLen * newLen;
|
||||
mY[ 0 ] = mY.at( 1 ) + ( mY.at( 0 ) - mY.at( 1 ) ) / currentLen * newLen;
|
||||
}
|
||||
// end of line
|
||||
if ( endDistance > 0 )
|
||||
{
|
||||
int last = mX.size() - 1;
|
||||
double currentLen = sqrt( qPow( mX.at( last ) - mX.at( last - 1 ), 2 ) +
|
||||
qPow( mY.at( last ) - mY.at( last - 1 ), 2 ) );
|
||||
double newLen = currentLen + endDistance;
|
||||
mX[ last ] = mX.at( last - 1 ) + ( mX.at( last ) - mX.at( last - 1 ) ) / currentLen * newLen;
|
||||
mY[ last ] = mY.at( last - 1 ) + ( mY.at( last ) - mY.at( last - 1 ) ) / currentLen * newLen;
|
||||
}
|
||||
}
|
||||
|
||||
/***************************************************************************
|
||||
* This class is considered CRITICAL and any change MUST be accompanied with
|
||||
* full unit tests.
|
||||
|
@ -120,6 +120,14 @@ class CORE_EXPORT QgsLineString: public QgsCurve
|
||||
@return the converted geometry. Caller takes ownership*/
|
||||
QgsAbstractGeometry* toCurveType() const override;
|
||||
|
||||
/**
|
||||
* Extends the line geometry by extrapolating out the start or end of the line
|
||||
* by a specified distance. Lines are extended using the bearing of the first or last
|
||||
* segment in the line.
|
||||
* @note added in QGIS 3.0
|
||||
*/
|
||||
void extend( double startDistance, double endDistance );
|
||||
|
||||
//reimplemented methods
|
||||
|
||||
virtual QString geometryType() const override { return QStringLiteral( "LineString" ); }
|
||||
|
@ -2208,6 +2208,16 @@ void TestQgsGeometry::lineString()
|
||||
QCOMPARE( static_cast< QgsPointV2*>( mpBoundary->geometryN( 1 ) )->x(), 1.0 );
|
||||
QCOMPARE( static_cast< QgsPointV2*>( mpBoundary->geometryN( 1 ) )->y(), 1.0 );
|
||||
QCOMPARE( static_cast< QgsPointV2*>( mpBoundary->geometryN( 1 ) )->z(), 20.0 );
|
||||
|
||||
|
||||
//extend
|
||||
QgsLineString extend1;
|
||||
extend1.extend( 10, 10 ); //test no crash
|
||||
extend1.setPoints( QList<QgsPointV2>() << QgsPointV2( 0, 0 ) << QgsPointV2( 1, 0 ) << QgsPointV2( 1, 1 ) );
|
||||
extend1.extend( 1, 2 );
|
||||
QCOMPARE( extend1.pointN( 0 ), QgsPointV2( QgsWkbTypes::Point, -1, 0 ) );
|
||||
QCOMPARE( extend1.pointN( 1 ), QgsPointV2( QgsWkbTypes::Point, 1, 0 ) );
|
||||
QCOMPARE( extend1.pointN( 2 ), QgsPointV2( QgsWkbTypes::Point, 1, 3 ) );
|
||||
}
|
||||
|
||||
void TestQgsGeometry::polygon()
|
||||
|
@ -3594,5 +3594,31 @@ class TestQgsGeometry(unittest.TestCase):
|
||||
self.assertAlmostEqual(polygon.angleAtVertex(3), math.radians(225.0), places=3)
|
||||
self.assertAlmostEqual(polygon.angleAtVertex(4), math.radians(135.0), places=3)
|
||||
|
||||
def testExtendLine(self):
|
||||
""" test QgsGeometry.extendLine """
|
||||
|
||||
empty = QgsGeometry()
|
||||
self.assertFalse(empty.extendLine(1, 2))
|
||||
|
||||
# not a linestring
|
||||
point = QgsGeometry.fromWkt('Point(1 2)')
|
||||
self.assertFalse(point.extendLine(1, 2))
|
||||
|
||||
# linestring
|
||||
linestring = QgsGeometry.fromWkt('LineString(0 0, 1 0, 1 1)')
|
||||
extended = linestring.extendLine(1, 2)
|
||||
exp = 'LineString(-1 0, 1 0, 1 3)'
|
||||
result = extended.exportToWkt()
|
||||
self.assertTrue(compareWkt(result, exp, 0.00001),
|
||||
"Extend line: mismatch Expected:\n{}\nGot:\n{}\n".format(exp, result))
|
||||
|
||||
# multilinestring
|
||||
multilinestring = QgsGeometry.fromWkt('MultiLineString((0 0, 1 0, 1 1),(11 11, 11 10, 10 10))')
|
||||
extended = multilinestring.extendLine(1, 2)
|
||||
exp = 'MultiLineString((-1 0, 1 0, 1 3),(11 12, 11 10, 8 10))'
|
||||
result = extended.exportToWkt()
|
||||
self.assertTrue(compareWkt(result, exp, 0.00001),
|
||||
"Extend line: mismatch Expected:\n{}\nGot:\n{}\n".format(exp, result))
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
|
Loading…
x
Reference in New Issue
Block a user