Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Single layer snapper fixes + optimisations #58029

Merged
merged 4 commits into from
Jul 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 25 additions & 21 deletions src/analysis/vector/qgsgeometrysnappersinglesource.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ static void assignAnchors( QgsSpatialIndex &index, QVector<AnchorPoint> &pnts, d
}


static bool snapPoint( QgsPoint *pt, QgsSpatialIndex &index, QVector<AnchorPoint> &pnts )
static bool snapPoint( QgsPoint *pt, const QgsSpatialIndex &index, const QVector<AnchorPoint> &pnts )
{
// Find point ( should always find one point )
QList<QgsFeatureId> fids = index.intersects( QgsRectangle( pt->x(), pt->y(), pt->x(), pt->y() ) );
Expand All @@ -153,16 +153,20 @@ static bool snapPoint( QgsPoint *pt, QgsSpatialIndex &index, QVector<AnchorPoint
}


static bool snapLineString( QgsLineString *linestring, QgsSpatialIndex &index, QVector<AnchorPoint> &pnts, double thresh )
static bool snapLineString( QgsLineString *linestring, const QgsSpatialIndex &index, const QVector<AnchorPoint> &pnts, double thresh )
{
const int lineStringSize = linestring->numPoints();
QVector<QgsPoint> newPoints;
QVector<int> anchors; // indexes of anchors for vertices
std::vector<int> anchors; // indexes of anchors for vertices
anchors.reserve( lineStringSize );
const double thresh2 = thresh * thresh;
double minDistX, minDistY; // coordinates of the closest point on the segment line
bool changed = false;

const AnchorPoint *pntsData = pnts.constData();

// snap vertices
for ( int v = 0; v < linestring->numPoints(); v++ )
for ( int v = 0; v < lineStringSize; v++ )
{
const double x = linestring->xAt( v );
const double y = linestring->yAt( v );
Expand All @@ -173,18 +177,18 @@ static bool snapLineString( QgsLineString *linestring, QgsSpatialIndex &index, Q
Q_ASSERT( fids.count() == 1 );

const int spoint = fids.first();
const int anchor = pnts[spoint].anchor;
const int anchor = pntsData[spoint].anchor;
if ( anchor >= 0 )
{
// to be snapped
linestring->setXAt( v, pnts[anchor].x );
linestring->setYAt( v, pnts[anchor].y );
anchors.append( anchor ); // point on new location
linestring->setXAt( v, pntsData[anchor].x );
linestring->setYAt( v, pntsData[anchor].y );
anchors.push_back( anchor ); // point on new location
changed = true;
}
else
{
anchors.append( spoint ); // old point
anchors.push_back( spoint ); // old point
}
}

Expand All @@ -210,7 +214,7 @@ static bool snapLineString( QgsLineString *linestring, QgsSpatialIndex &index, Q
// Find points
const QList<QgsFeatureId> fids = index.intersects( rect );

QVector<AnchorAlongSegment> newVerticesAlongSegment;
std::vector<AnchorAlongSegment> newVerticesAlongSegment;

// Snap to anchor in threshold different from end points
for ( const QgsFeatureId fid : fids )
Expand All @@ -234,11 +238,11 @@ static bool snapLineString( QgsLineString *linestring, QgsSpatialIndex &index, Q
AnchorAlongSegment item;
item.anchor = spoint;
item.along = QgsPointXY( x1, y1 ).distance( minDistX, minDistY );
newVerticesAlongSegment << item;
newVerticesAlongSegment.push_back( item );
}
}

if ( !newVerticesAlongSegment.isEmpty() )
if ( !newVerticesAlongSegment.empty() )
{
// sort by distance along the segment
std::sort( newVerticesAlongSegment.begin(), newVerticesAlongSegment.end(), []( AnchorAlongSegment p1, AnchorAlongSegment p2 )
Expand All @@ -247,10 +251,10 @@ static bool snapLineString( QgsLineString *linestring, QgsSpatialIndex &index, Q
} );

// insert new vertices
for ( int i = 0; i < newVerticesAlongSegment.count(); i++ )
for ( const AnchorAlongSegment &vertex : newVerticesAlongSegment )
{
const int anchor = newVerticesAlongSegment[i].anchor;
newPoints << QgsPoint( pnts[anchor].x, pnts[anchor].y, 0 );
const int anchor = vertex.anchor;
newPoints << QgsPoint( pntsData[anchor].x, pntsData[anchor].y, 0 );
}
changed = true;
}
Expand All @@ -267,31 +271,31 @@ static bool snapLineString( QgsLineString *linestring, QgsSpatialIndex &index, Q
}


static bool snapGeometry( QgsAbstractGeometry *g, QgsSpatialIndex &index, QVector<AnchorPoint> &pnts, double thresh )
static bool snapGeometry( QgsAbstractGeometry *g, const QgsSpatialIndex &index, const QVector<AnchorPoint> &pnts, double thresh )
{
bool changed = false;
if ( QgsLineString *linestring = qgsgeometry_cast<QgsLineString *>( g ) )
{
changed |= snapLineString( linestring, index, pnts, thresh );
changed = snapLineString( linestring, index, pnts, thresh ) | changed;
}
else if ( QgsPolygon *polygon = qgsgeometry_cast<QgsPolygon *>( g ) )
{
if ( QgsLineString *exteriorRing = qgsgeometry_cast<QgsLineString *>( polygon->exteriorRing() ) )
changed |= snapLineString( exteriorRing, index, pnts, thresh );
changed = snapLineString( exteriorRing, index, pnts, thresh ) | changed;
for ( int i = 0; i < polygon->numInteriorRings(); ++i )
{
if ( QgsLineString *interiorRing = qgsgeometry_cast<QgsLineString *>( polygon->interiorRing( i ) ) )
changed |= snapLineString( interiorRing, index, pnts, thresh );
changed = snapLineString( interiorRing, index, pnts, thresh ) | changed;
}
}
else if ( QgsGeometryCollection *collection = qgsgeometry_cast<QgsGeometryCollection *>( g ) )
{
for ( int i = 0; i < collection->numGeometries(); ++i )
changed |= snapGeometry( collection->geometryN( i ), index, pnts, thresh );
changed = snapGeometry( collection->geometryN( i ), index, pnts, thresh ) | changed;
}
else if ( QgsPoint *pt = qgsgeometry_cast<QgsPoint *>( g ) )
{
changed |= snapPoint( pt, index, pnts );
changed = snapPoint( pt, index, pnts ) | changed;
}

return changed;
Expand Down
13 changes: 8 additions & 5 deletions src/core/geometry/qgslinestring.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1992,18 +1992,21 @@ double QgsLineString::closestSegment( const QgsPoint &pt, QgsPoint &segmentPt,
if ( leftOf )
*leftOf = 0;

int size = mX.size();
const int size = mX.size();
if ( size == 0 || size == 1 )
{
vertexAfter = QgsVertexId( 0, 0, 0 );
return -1;
}

const double *xData = mX.constData();
const double *yData = mY.constData();
for ( int i = 1; i < size; ++i )
{
double prevX = mX.at( i - 1 );
double prevY = mY.at( i - 1 );
double currentX = mX.at( i );
double currentY = mY.at( i );
double prevX = xData[ i - 1 ];
double prevY = yData[ i - 1 ];
double currentX = xData[ i ];
double currentY = yData[ i ];
testDist = QgsGeometryUtilsBase::sqrDistToLine( pt.x(), pt.y(), prevX, prevY, currentX, currentY, segmentPtX, segmentPtY, epsilon );
if ( testDist < sqrDist )
{
Expand Down
Loading