bool QgsSnapIndex::SegmentSnapItem::getIntersection( const QgsPoint &p1, const QgsPoint &p2, QgsPoint &inter ) const { const QgsPoint &q1 = idxFrom->point(), & q2 = idxTo->point(); QgsVector v( p2.x() - p1.x(), p2.y() - p1.y() ); QgsVector w( q2.x() - q1.x(), q2.y() - q1.y() ); double vl = v.length(); double wl = w.length(); if ( qgsDoubleNear( vl, 0, 0.000000000001 ) || qgsDoubleNear( wl, 0, 0.000000000001 ) ) { return false; } v = v / vl; w = w / wl; double d = v.y() * w.x() - v.x() * w.y(); if ( d == 0 ) return false; double dx = q1.x() - p1.x(); double dy = q1.y() - p1.y(); double k = ( dy * w.x() - dx * w.y() ) / d; inter = QgsPoint( p1.x() + v.x() * k, p1.y() + v.y() * k ); double lambdav = QgsVector( inter.x() - p1.x(), inter.y() - p1.y() ) * v; if ( lambdav < 0. + 1E-8 || lambdav > vl - 1E-8 ) return false; double lambdaw = QgsVector( inter.x() - q1.x(), inter.y() - q1.y() ) * w; return !( lambdaw < 0. + 1E-8 || lambdaw >= wl - 1E-8 ); }
bool QgsGeometryUtils::segmentIntersection( const QgsPointV2 &p1, const QgsPointV2 &p2, const QgsPointV2 &q1, const QgsPointV2 &q2, QgsPointV2 &inter, double tolerance ) { QgsVector v( p2.x() - p1.x(), p2.y() - p1.y() ); QgsVector w( q2.x() - q1.x(), q2.y() - q1.y() ); double vl = v.length(); double wl = w.length(); if ( qFuzzyIsNull( vl ) || qFuzzyIsNull( wl ) ) { return false; } v = v / vl; w = w / wl; if ( !QgsGeometryUtils::lineIntersection( p1, v, q1, w, inter ) ) return false; double lambdav = QgsVector( inter.x() - p1.x(), inter.y() - p1.y() ) * v; if ( lambdav < 0. + tolerance || lambdav > vl - tolerance ) return false; double lambdaw = QgsVector( inter.x() - q1.x(), inter.y() - q1.y() ) * w; if ( lambdaw < 0. + tolerance || lambdaw >= wl - tolerance ) return false; return true; }
QgsVector calcMotion( const QgsPoint &a, const QgsPoint &b, const QgsPoint &c, double lowerThreshold, double upperThreshold ) { QgsVector p = a - b; QgsVector q = c - b; if ( qgsDoubleNear( p.length(), 0.0 ) || qgsDoubleNear( q.length(), 0.0 ) ) return QgsVector( 0, 0 ); // 2.0 is a magic number from the original JOSM source code double scale = 2.0 * std::min( p.length(), q.length() ); p = p.normalized(); q = q.normalized(); double dotProduct = p * q; if ( !dotProductWithinAngleTolerance( dotProduct, lowerThreshold, upperThreshold ) ) { return QgsVector( 0, 0 ); } // wonderful nasty hack which has survived through JOSM -> id -> QGIS // to deal with almost-straight segments (angle is closer to 180 than to 90/270). if ( dotProduct < -M_SQRT1_2 ) dotProduct += 1.0; QgsVector new_v = p + q; // 0.1 magic number from JOSM implementation - think this is to limit each iterative step return new_v.normalized() * ( 0.1 * dotProduct * scale ); }
void QgsHighlight::paintPoint( QPainter *p, QgsPoint point ) { QPolygonF r( 5 ); double d = mMapCanvas->extent().width() * 0.005; r[0] = toCanvasCoordinates( point + QgsVector( -d, -d ) ) - pos(); r[1] = toCanvasCoordinates( point + QgsVector( d, -d ) ) - pos(); r[2] = toCanvasCoordinates( point + QgsVector( d, d ) ) - pos(); r[3] = toCanvasCoordinates( point + QgsVector( -d, d ) ) - pos(); r[4] = r[0]; p->drawPolygon( r ); }
void QgsGeometryAngleCheck::collectErrors( QList<QgsGeometryCheckError *> &errors, QStringList &/*messages*/, QAtomicInt *progressCounter, const QgsFeatureIds &ids ) const { const QgsFeatureIds &featureIds = ids.isEmpty() ? mFeaturePool->getFeatureIds() : ids; Q_FOREACH ( QgsFeatureId featureid, featureIds ) { if ( progressCounter ) progressCounter->fetchAndAddRelaxed( 1 ); QgsFeature feature; if ( !mFeaturePool->get( featureid, feature ) ) { continue; } QgsGeometry g = feature.geometry(); const QgsAbstractGeometry *geom = g.geometry(); for ( int iPart = 0, nParts = geom->partCount(); iPart < nParts; ++iPart ) { for ( int iRing = 0, nRings = geom->ringCount( iPart ); iRing < nRings; ++iRing ) { int nVerts = QgsGeometryCheckerUtils::polyLineSize( geom, iPart, iRing ); // Less than three points, no angles to check if ( nVerts < 3 ) { continue; } for ( int iVert = 0; iVert < nVerts; ++iVert ) { const QgsPoint &p1 = geom->vertexAt( QgsVertexId( iPart, iRing, ( iVert - 1 + nVerts ) % nVerts ) ); const QgsPoint &p2 = geom->vertexAt( QgsVertexId( iPart, iRing, iVert ) ); const QgsPoint &p3 = geom->vertexAt( QgsVertexId( iPart, iRing, ( iVert + 1 ) % nVerts ) ); QgsVector v21, v23; try { v21 = QgsVector( p1.x() - p2.x(), p1.y() - p2.y() ).normalized(); v23 = QgsVector( p3.x() - p2.x(), p3.y() - p2.y() ).normalized(); } catch ( const QgsException & ) { // Zero length vectors continue; } double angle = std::acos( v21 * v23 ) / M_PI * 180.0; if ( angle < mMinAngle ) { errors.append( new QgsGeometryCheckError( this, featureid, p2, QgsVertexId( iPart, iRing, iVert ), angle ) ); } } } } } }
void QgsHighlight::paintPoint( QPainter *p, QgsPoint point ) { QPolygonF r( 5 ); if ( mLayer ) { point = mMapCanvas->mapRenderer()->layerToMapCoordinates( mLayer, point ); } double d = mMapCanvas->extent().width() * 0.005; r[0] = toCanvasCoordinates( point + QgsVector( -d, -d ) ) - pos(); r[1] = toCanvasCoordinates( point + QgsVector( d, -d ) ) - pos(); r[2] = toCanvasCoordinates( point + QgsVector( d, d ) ) - pos(); r[3] = toCanvasCoordinates( point + QgsVector( -d, d ) ) - pos(); r[4] = r[0]; p->drawPolygon( r ); }
void TestQgsRectangle::operators() { QgsRectangle rect1 = QgsRectangle( 10.0, 20.0, 110.0, 220.0 ); QgsVector v = QgsVector( 1.0, 2.0 ); QgsRectangle rect2 = rect1 + v; QVERIFY( rect1 != rect2 ); QCOMPARE( rect2.height(), rect1.height() ); QCOMPARE( rect2.width(), rect1.width() ); QCOMPARE( rect2.xMinimum(), 11.0 ); QCOMPARE( rect2.yMinimum(), 22.0 ); rect2 -= rect2.center() - rect1.center(); QVERIFY( rect1 == rect2 ); rect2 += v * 2.5; QCOMPARE( rect2.xMinimum(), 12.5 ); QCOMPARE( rect2.yMinimum(), 25.0 ); rect2 = rect1 - v; QCOMPARE( rect2.xMinimum(), 9.0 ); QCOMPARE( rect2.yMinimum(), 18.0 ); QCOMPARE( rect2.height(), rect1.height() ); QCOMPARE( rect2.width(), rect1.width() ); }
QgsVector QgsVector::operator*( double scalar ) const { return QgsVector( mX * scalar, mY * scalar ); }
QgsVector QgsVector::operator-() const { return QgsVector( -mX, -mY ); }
void QgsGeometryAngleCheck::fixError( QgsGeometryCheckError* error, int method, int /*mergeAttributeIndex*/, Changes &changes ) const { QgsFeature feature; if ( !mFeaturePool->get( error->featureId(), feature ) ) { error->setObsolete(); return; } QgsAbstractGeometryV2* geometry = feature.geometry()->geometry(); const QgsVertexId& vidx = error->vidx(); // Check if point still exists if ( !vidx.isValid( geometry ) ) { error->setObsolete(); return; } // Check if error still applies int n = QgsGeomUtils::polyLineSize( geometry, vidx.part, vidx.ring ); const QgsPointV2& p1 = geometry->vertexAt( QgsVertexId( vidx.part, vidx.ring, ( vidx.vertex - 1 + n ) % n ) ); const QgsPointV2& p2 = geometry->vertexAt( vidx ); const QgsPointV2& p3 = geometry->vertexAt( QgsVertexId( vidx.part, vidx.ring, ( vidx.vertex + 1 ) % n ) ); QgsVector v21, v23; try { v21 = QgsVector( p1.x() - p2.x(), p1.y() - p2.y() ).normal(); v23 = QgsVector( p3.x() - p2.x(), p3.y() - p2.y() ).normal(); } catch ( const QgsException& ) { error->setObsolete(); return; } double angle = std::acos( v21 * v23 ) / M_PI * 180.0; if ( angle >= mMinAngle ) { error->setObsolete(); return; } // Fix error if ( method == NoChange ) { error->setFixed( method ); } else if ( method == DeleteNode ) { if ( n <= 3 ) { error->setFixFailed( tr( "Resulting geometry is degenerate" ) ); } else { geometry->deleteVertex( vidx ); mFeaturePool->updateFeature( feature ); error->setFixed( method ); changes[error->featureId()].append( Change( ChangeNode, ChangeRemoved, vidx ) ); } } else { error->setFixFailed( tr( "Unknown method" ) ); } }
QgsVector QgsVector::operator-( QgsVector other ) const { return QgsVector( mX - other.mX, mY - other.mY ); }
QgsVector QgsVector::operator+( QgsVector other ) const { return QgsVector( mX + other.mX, mY + other.mY ); }
QgsVector QgsVector::operator-( void ) const { return QgsVector( -m_x, -m_y ); }
QgsLineString *doOrthogonalize( QgsLineString *ring, int iterations, double tolerance, double lowerThreshold, double upperThreshold ) { double minScore = DBL_MAX; bool isClosed = ring->isClosed(); int numPoints = ring->numPoints(); std::unique_ptr< QgsLineString > best( ring->clone() ); QVector< QgsVector > /* yep */ motions; motions.reserve( numPoints ); for ( int it = 0; it < iterations; ++it ) { motions.resize( 0 ); // avoid re-allocations // first loop through an calculate all motions QgsPoint a; QgsPoint b; QgsPoint c; for ( int i = 0; i < numPoints; ++i ) { if ( isClosed && i == numPoints - 1 ) motions << motions.at( 0 ); //closed ring, so last point follows first point motion else if ( !isClosed && ( i == 0 || i == numPoints - 1 ) ) { b = ring->pointN( 0 ); c = ring->pointN( 1 ); motions << QgsVector( 0, 0 ); //non closed line, leave first/last vertex untouched } else { if ( i == 0 ) { a = ring->pointN( numPoints - 1 ); b = ring->pointN( 0 ); } if ( i == numPoints - 1 ) c = ring->pointN( 0 ); else c = ring->pointN( i + 1 ); motions << calcMotion( a, b, c, lowerThreshold, upperThreshold ); } a = b; b = c; } // then apply them for ( int i = 0; i < numPoints; ++i ) { ring->setXAt( i, ring->xAt( i ) + motions.at( i ).x() ); ring->setYAt( i, ring->yAt( i ) + motions.at( i ).y() ); } double newScore = squareness( ring, lowerThreshold, upperThreshold ); if ( newScore < minScore ) { best.reset( ring->clone() ); minScore = newScore; } if ( minScore < tolerance ) break; } delete ring; return best.release(); }
void QgsGeometryAngleCheck::fixError( QgsGeometryCheckError *error, int method, int /*mergeAttributeIndex*/, Changes &changes ) const { QgsFeature feature; if ( !mFeaturePool->get( error->featureId(), feature ) ) { error->setObsolete(); return; } QgsGeometry g = feature.geometry(); QgsAbstractGeometry *geometry = g.geometry(); QgsVertexId vidx = error->vidx(); // Check if point still exists if ( !vidx.isValid( geometry ) ) { error->setObsolete(); return; } // Check if error still applies int n = QgsGeometryCheckerUtils::polyLineSize( geometry, vidx.part, vidx.ring ); if ( n == 0 ) { error->setObsolete(); return; } const QgsPoint &p1 = geometry->vertexAt( QgsVertexId( vidx.part, vidx.ring, ( vidx.vertex - 1 + n ) % n ) ); const QgsPoint &p2 = geometry->vertexAt( vidx ); const QgsPoint &p3 = geometry->vertexAt( QgsVertexId( vidx.part, vidx.ring, ( vidx.vertex + 1 ) % n ) ); QgsVector v21, v23; try { v21 = QgsVector( p1.x() - p2.x(), p1.y() - p2.y() ).normalized(); v23 = QgsVector( p3.x() - p2.x(), p3.y() - p2.y() ).normalized(); } catch ( const QgsException & ) { error->setObsolete(); return; } double angle = std::acos( v21 * v23 ) / M_PI * 180.0; if ( angle >= mMinAngle ) { error->setObsolete(); return; } // Fix error if ( method == NoChange ) { error->setFixed( method ); } else if ( method == DeleteNode ) { if ( !QgsGeometryCheckerUtils::canDeleteVertex( geometry, vidx.part, vidx.ring ) ) { error->setFixFailed( tr( "Resulting geometry is degenerate" ) ); } else if ( !geometry->deleteVertex( error->vidx() ) ) { error->setFixFailed( tr( "Failed to delete vertex" ) ); } else { changes[error->featureId()].append( Change( ChangeNode, ChangeRemoved, vidx ) ); if ( QgsGeometryUtils::sqrDistance2D( p1, p3 ) < QgsGeometryCheckPrecision::tolerance() * QgsGeometryCheckPrecision::tolerance() && QgsGeometryCheckerUtils::canDeleteVertex( geometry, vidx.part, vidx.ring ) && geometry->deleteVertex( error->vidx() ) ) // error->vidx points to p3 after removing p2 { changes[error->featureId()].append( Change( ChangeNode, ChangeRemoved, QgsVertexId( vidx.part, vidx.ring, ( vidx.vertex + 1 ) % n ) ) ); } feature.setGeometry( g ); mFeaturePool->updateFeature( feature ); error->setFixed( method ); } } else { error->setFixFailed( tr( "Unknown method" ) ); } }
QgsVector QgsVector::operator+( const QgsVector& v ) const { return QgsVector( m_x + v.m_x, m_y + v.m_y ); }
QgsVector QgsVector::operator-( const QgsVector& v ) const { return QgsVector( m_x - v.m_x, m_y - v.m_y ); }
// perpendicular vector (rotated 90 degrees counter-clockwise) QgsVector QgsVector::perpVector() const { return QgsVector( -m_y, m_x ); }
QgsVector QgsVector::operator*( double scalar ) const { return QgsVector( m_x * scalar, m_y * scalar ); }
QgsVector QgsVector::perpVector() const { return QgsVector( -mY, mX ); }
QgsVector QgsVector::rotateBy( double rot ) const { double ang = atan2( mY, mX ) + rot; double len = length(); return QgsVector( len * cos( ang ), len * sin( ang ) ); }
QgsVector QgsVector::rotateBy( double rot ) const { double theAngle = atan2( mY, mX ) + rot; double len = length(); return QgsVector( len * cos( theAngle ), len * sin( theAngle ) ); }