double QgsLineStringV2::closestSegment( const QgsPointV2& pt, QgsPointV2& segmentPt, QgsVertexId& vertexAfter, bool* leftOf, double epsilon ) const { double sqrDist = std::numeric_limits<double>::max(); double testDist = 0; double segmentPtX, segmentPtY; int size = mCoords.size(); for ( int i = 1; i < size; ++i ) { const QPointF& prev = mCoords.at( i - 1 ); const QPointF& currentPt = mCoords.at( i ); testDist = QgsGeometryUtils::sqrDistToLine( pt.x(), pt.y(), prev.x(), prev.y(), currentPt.x(), currentPt.y(), segmentPtX, segmentPtY, epsilon ); if ( testDist < sqrDist ) { sqrDist = testDist; segmentPt.setX( segmentPtX ); segmentPt.setY( segmentPtY ); if ( leftOf ) { *leftOf = ( QgsGeometryUtils::leftOfLine( segmentPtX, segmentPtY, prev.x(), prev.y(), pt.x(), pt.y() ) < 0 ); } vertexAfter.part = 0; vertexAfter.ring = 0; vertexAfter.vertex = i; } } return sqrDist; }
double QgsLineString::closestSegment( const QgsPointV2& pt, QgsPointV2& segmentPt, QgsVertexId& vertexAfter, bool* leftOf, double epsilon ) const { double sqrDist = std::numeric_limits<double>::max(); double testDist = 0; double segmentPtX, segmentPtY; int size = mX.size(); if ( size == 0 || size == 1 ) { vertexAfter = QgsVertexId( 0, 0, 0 ); return -1; } 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 ); testDist = QgsGeometryUtils::sqrDistToLine( pt.x(), pt.y(), prevX, prevY, currentX, currentY, segmentPtX, segmentPtY, epsilon ); if ( testDist < sqrDist ) { sqrDist = testDist; segmentPt.setX( segmentPtX ); segmentPt.setY( segmentPtY ); if ( leftOf ) { *leftOf = ( QgsGeometryUtils::leftOfLine( pt.x(), pt.y(), prevX, prevY, currentX, currentY ) < 0 ); } vertexAfter.part = 0; vertexAfter.ring = 0; vertexAfter.vertex = i; } } return sqrDist; }
void QgsSelectedFeature::moveSelectedVertexes( QgsVector v ) { int nUpdates = 0; Q_FOREACH ( QgsVertexEntry *entry, mVertexMap ) { if ( entry->isSelected() ) nUpdates++; } if ( nUpdates == 0 ) return; mVlayer->beginEditCommand( QObject::tr( "Moved vertices" ) ); int topologicalEditing = QgsProject::instance()->readNumEntry( "Digitizing", "/TopologicalEditing", 0 ); beginGeometryChange(); QMultiMap<double, QgsSnappingResult> currentResultList; for ( int i = mVertexMap.size() - 1; i > -1 && nUpdates > 0; i-- ) { QgsVertexEntry *entry = mVertexMap.value( i, nullptr ); if ( !entry || !entry->isSelected() ) continue; if ( topologicalEditing ) { // snap from current vertex currentResultList.clear(); mVlayer->snapWithContext( entry->pointV1(), ZERO_TOLERANCE, currentResultList, QgsSnapper::SnapToVertex ); } // only last update should trigger the geometry update // as vertex selection gets lost on the update if ( --nUpdates == 0 ) endGeometryChange(); QgsPointV2 p = entry->point(); p.setX( p.x() + v.x() ); p.setY( p.y() + v.y() ); mVlayer->moveVertex( p, mFeatureId, i ); if ( topologicalEditing ) { QMultiMap<double, QgsSnappingResult>::iterator resultIt = currentResultList.begin(); for ( ; resultIt != currentResultList.end(); ++resultIt ) { // move all other if ( mFeatureId != resultIt.value().snappedAtGeometry ) mVlayer->moveVertex( p, resultIt.value().snappedAtGeometry, resultIt.value().snappedVertexNr ); } } } if ( nUpdates > 0 ) endGeometryChange(); mVlayer->endEditCommand(); }
double QgsCircularString::closestPointOnArc( double x1, double y1, double x2, double y2, double x3, double y3, const QgsPointV2 &pt, QgsPointV2 &segmentPt, QgsVertexId &vertexAfter, bool *leftOf, double epsilon ) { double radius, centerX, centerY; QgsPointV2 pt1( x1, y1 ); QgsPointV2 pt2( x2, y2 ); QgsPointV2 pt3( x3, y3 ); QgsGeometryUtils::circleCenterRadius( pt1, pt2, pt3, radius, centerX, centerY ); double angle = QgsGeometryUtils::ccwAngle( pt.y() - centerY, pt.x() - centerX ); double angle1 = QgsGeometryUtils::ccwAngle( pt1.y() - centerY, pt1.x() - centerX ); double angle2 = QgsGeometryUtils::ccwAngle( pt2.y() - centerY, pt2.x() - centerX ); double angle3 = QgsGeometryUtils::ccwAngle( pt3.y() - centerY, pt3.x() - centerX ); bool clockwise = QgsGeometryUtils::circleClockwise( angle1, angle2, angle3 ); if ( QgsGeometryUtils::angleOnCircle( angle, angle1, angle2, angle3 ) ) { //get point on line center -> pt with distance radius segmentPt = QgsGeometryUtils::pointOnLineWithDistance( QgsPointV2( centerX, centerY ), pt, radius ); //vertexAfter vertexAfter.vertex = QgsGeometryUtils::circleAngleBetween( angle, angle1, angle2, clockwise ) ? 1 : 2; } else { double distPtPt1 = QgsGeometryUtils::sqrDistance2D( pt, pt1 ); double distPtPt3 = QgsGeometryUtils::sqrDistance2D( pt, pt3 ); segmentPt = ( distPtPt1 <= distPtPt3 ) ? pt1 : pt3; vertexAfter.vertex = ( distPtPt1 <= distPtPt3 ) ? 1 : 2; } double sqrDistance = QgsGeometryUtils::sqrDistance2D( segmentPt, pt ); //prevent rounding errors if the point is directly on the segment if ( qgsDoubleNear( sqrDistance, 0.0, epsilon ) ) { segmentPt.setX( pt.x() ); segmentPt.setY( pt.y() ); sqrDistance = 0.0; } if ( leftOf ) { *leftOf = clockwise ? sqrDistance > radius : sqrDistance < radius; } return sqrDistance; }