bool QgsLineStringV2::moveVertex( const QgsVertexId& position, const QgsPointV2& newPos ) { if ( position.vertex < 0 || position.vertex >= mCoords.size() ) { return false; } mCoords[position.vertex].rx() = newPos.x(); mCoords[position.vertex].ry() = newPos.y(); if ( is3D() && newPos.is3D() ) { mZ[position.vertex] = newPos.z(); } if ( isMeasure() && newPos.isMeasure() ) { mM[position.vertex] = newPos.m(); } mBoundingBox = QgsRectangle(); //set bounding box invalid return true; }
bool QgsCircularString::moveVertex( QgsVertexId position, const QgsPointV2 &newPos ) { if ( position.vertex < 0 || position.vertex >= mX.size() ) { return false; } mX[position.vertex] = newPos.x(); mY[position.vertex] = newPos.y(); if ( is3D() && newPos.is3D() ) { mZ[position.vertex] = newPos.z(); } if ( isMeasure() && newPos.isMeasure() ) { mM[position.vertex] = newPos.m(); } clearCache(); //set bounding box invalid return true; }
void QgsGeometryRubberBand::paint( QPainter* painter ) { if ( !mGeometry || !painter ) { return; } painter->save(); painter->translate( -pos() ); if ( mGeometryType == QGis::Polygon ) { painter->setBrush( mBrush ); } else { painter->setBrush( Qt::NoBrush ); } painter->setPen( mPen ); QgsAbstractGeometryV2* paintGeom = mGeometry->clone(); paintGeom->transform( mMapCanvas->getCoordinateTransform()->transform() ); paintGeom->draw( *painter ); //draw vertices QgsVertexId vertexId; QgsPointV2 vertex; while ( paintGeom->nextVertex( vertexId, vertex ) ) { drawVertex( painter, vertex.x(), vertex.y() ); } delete paintGeom; painter->restore(); }
bool QgsSnapIndex::SegmentSnapItem::getIntersection( const QgsPointV2 &p1, const QgsPointV2 &p2, QgsPointV2& inter ) const { const QgsPointV2& 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 ( qFuzzyIsNull( vl ) || qFuzzyIsNull( wl ) ) { 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 = QgsPointV2( 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; if ( lambdaw < 0. + 1E-8 || lambdaw >= wl - 1E-8 ) return false; return true; }
double QgsGeometryUtils::sqrDistance2D( const QgsPointV2& pt1, const QgsPointV2& pt2 ) { return ( pt1.x() - pt2.x() ) * ( pt1.x() - pt2.x() ) + ( pt1.y() - pt2.y() ) * ( pt1.y() - pt2.y() ); }
/** * Calculate the area of a triangle in 2d */ static double triarea2d( const QgsPointV2 &P1, const QgsPointV2 &P2, const QgsPointV2 &P3 ) { return qAbs( 0.5 * (( P1.x() - P2.x() ) * ( P3.y() - P2.y() ) - ( P1.y() - P2.y() ) * ( P3.x() - P2.x() ) ) ); }
void QgsMapToolCircularStringRadius::cadCanvasReleaseEvent( QgsMapMouseEvent* e ) { QgsPointV2 mapPoint( e->mapPoint().x(), e->mapPoint().y() ); if ( e->button() == Qt::LeftButton ) { if ( mPoints.isEmpty() ) { //get first point from parent tool if there. Todo: move to upper class const QgsCompoundCurveV2* compoundCurve = mParentTool->captureCurve(); if ( compoundCurve && compoundCurve->nCurves() > 0 ) { const QgsCurveV2* curve = compoundCurve->curveAt( compoundCurve->nCurves() - 1 ); if ( curve ) { //mParentTool->captureCurve() is in layer coordinates, but we need map coordinates QgsPointV2 endPointLayerCoord = curve->endPoint(); QgsPoint mapPoint = toMapCoordinates( mCanvas->currentLayer(), QgsPoint( endPointLayerCoord.x(), endPointLayerCoord.y() ) ); mPoints.append( QgsPointV2( mapPoint.x(), mapPoint.y() ) ); } } else { mPoints.append( mapPoint ); return; } } if ( mPoints.size() % 2 == 1 ) { if ( !mRadiusMode ) { delete mRubberBand; mRubberBand = 0; mTemporaryEndPointX = mapPoint.x(); mTemporaryEndPointY = mapPoint.y(); mRadiusMode = true; //initial radius is distance( tempPoint - mPoints.last ) / 2.0 double minRadius = sqrt( QgsGeometryUtils::sqrDistance2D( mPoints.last(), QgsPointV2( mTemporaryEndPointX, mTemporaryEndPointY ) ) ) / 2.0; mRadius = minRadius + minRadius / 10.0; recalculateCircularString(); createRadiusSpinBox(); if ( mRadiusSpinBox ) { mRadiusSpinBox->setMinimum( minRadius ); } } else { QgsPointV2 result; if ( QgsGeometryUtils::segmentMidPoint( mPoints.last(), QgsPointV2( mTemporaryEndPointX, mTemporaryEndPointY ), result, mRadius, QgsPointV2( mapPoint.x(), mapPoint.y() ) ) ) { mPoints.append( result ); mPoints.append( QgsPointV2( mTemporaryEndPointX, mTemporaryEndPointY ) ); } mRadiusMode = false; deleteRadiusSpinBox(); } } else { //can we get there? } } else if ( e->button() == Qt::RightButton ) { deactivate(); if ( mParentTool ) { mParentTool->canvasReleaseEvent( e ); } } }
void QgsGeometryUtils::circleCenterRadius( const QgsPointV2& pt1, const QgsPointV2& pt2, const QgsPointV2& pt3, double& radius, double& centerX, double& centerY ) { double dx21, dy21, dx31, dy31, h21, h31, d; //closed circle if ( qgsDoubleNear( pt1.x(), pt3.x() ) && qgsDoubleNear( pt1.y(), pt3.y() ) ) { centerX = pt2.x(); centerY = pt2.y(); radius = sqrt( pow( pt2.x() - pt1.x(), 2.0 ) + pow( pt2.y() - pt1.y(), 2.0 ) ); return; } // Using cartesian circumcenter eguations from page https://en.wikipedia.org/wiki/Circumscribed_circle dx21 = pt2.x() - pt1.x(); dy21 = pt2.y() - pt1.y(); dx31 = pt3.x() - pt1.x(); dy31 = pt3.y() - pt1.y(); h21 = pow( dx21, 2.0 ) + pow( dy21, 2.0 ); h31 = pow( dx31, 2.0 ) + pow( dy31, 2.0 ); // 2*Cross product, d<0 means clockwise and d>0 counterclockwise sweeping angle d = 2 * ( dx21 * dy31 - dx31 * dy21 ); // Check colinearity, Cross product = 0 if ( qgsDoubleNear( fabs( d ), 0.0, 0.00000000001 ) ) { radius = -1.0; return; } // Calculate centroid coordinates and radius centerX = pt1.x() + ( h21 * dy31 - h31 * dy21 ) / d; centerY = pt1.y() - ( h21 * dx31 - h31 * dx21 ) / d; radius = sqrt( pow( centerX - pt1.x(), 2.0 ) + pow( centerY - pt1.y(), 2.0 ) ); }
void QgsMapToolIdentify::closestVertexAttributes( const QgsAbstractGeometry& geometry, QgsVertexId vId, QgsMapLayer *layer, QMap< QString, QString >& derivedAttributes ) { QString str = QLocale::system().toString( vId.vertex + 1 ); derivedAttributes.insert( tr( "Closest vertex number" ), str ); QgsPointV2 closestPoint = geometry.vertexAt( vId ); QgsPoint closestPointMapCoords = mCanvas->mapSettings().layerToMapCoordinates( layer, QgsPoint( closestPoint.x(), closestPoint.y() ) ); derivedAttributes.insert( "Closest vertex X", formatXCoordinate( closestPointMapCoords ) ); derivedAttributes.insert( "Closest vertex Y", formatYCoordinate( closestPointMapCoords ) ); if ( closestPoint.is3D() ) { str = QLocale::system().toString( closestPoint.z(), 'g', 10 ); derivedAttributes.insert( "Closest vertex Z", str ); } if ( closestPoint.isMeasure() ) { str = QLocale::system().toString( closestPoint.m(), 'g', 10 ); derivedAttributes.insert( "Closest vertex M", str ); } if ( vId.type == QgsVertexId::CurveVertex ) { double radius, centerX, centerY; QgsVertexId vIdBefore = vId; --vIdBefore.vertex; QgsVertexId vIdAfter = vId; ++vIdAfter.vertex; QgsGeometryUtils::circleCenterRadius( geometry.vertexAt( vIdBefore ), geometry.vertexAt( vId ), geometry.vertexAt( vIdAfter ), radius, centerX, centerY ); derivedAttributes.insert( "Closest vertex radius", QLocale::system().toString( radius ) ); } }
void QgsMapToolAddCircularString::activate() { if ( mParentTool ) { mParentTool->deleteTempRubberBand(); if ( mPoints.isEmpty() ) { // if the parent tool has a curve, use its last point as the first point in this curve const QgsCompoundCurveV2* compoundCurve = mParentTool->captureCurve(); if ( compoundCurve && compoundCurve->nCurves() > 0 ) { const QgsCurveV2* curve = compoundCurve->curveAt( compoundCurve->nCurves() - 1 ); if ( curve ) { //mParentTool->captureCurve() is in layer coordinates, but we need map coordinates QgsPointV2 endPointLayerCoord = curve->endPoint(); QgsPoint mapPoint = toMapCoordinates( mCanvas->currentLayer(), QgsPoint( endPointLayerCoord.x(), endPointLayerCoord.y() ) ); mPoints.append( QgsPointV2( mapPoint ) ); if ( !mTempRubberBand ) { mTempRubberBand = createGeometryRubberBand(( mode() == CapturePolygon ) ? Qgis::Polygon : Qgis::Line, true ); mTempRubberBand->show(); } QgsCircularStringV2* c = new QgsCircularStringV2(); QgsPointSequenceV2 rubberBandPoints = mPoints; rubberBandPoints.append( QgsPointV2( mapPoint ) ); c->setPoints( rubberBandPoints ); mTempRubberBand->setGeometry( c ); } } } } QgsMapToolCapture::activate(); }
void QgsMapToolAddFeature::cadCanvasReleaseEvent( QgsMapMouseEvent* e ) { QgsVectorLayer* vlayer = currentVectorLayer(); if ( !vlayer ) { notifyNotVectorLayer(); return; } QgsWkbTypes::Type layerWKBType = vlayer->wkbType(); QgsVectorDataProvider* provider = vlayer->dataProvider(); if ( !( provider->capabilities() & QgsVectorDataProvider::AddFeatures ) ) { emit messageEmitted( tr( "The data provider for this layer does not support the addition of features." ), QgsMessageBar::WARNING ); return; } if ( !vlayer->isEditable() ) { notifyNotEditableLayer(); return; } // POINT CAPTURING if ( mode() == CapturePoint ) { if ( e->button() != Qt::LeftButton ) return; //check we only use this tool for point/multipoint layers if ( vlayer->geometryType() != QgsWkbTypes::PointGeometry && mCheckGeometryType ) { emit messageEmitted( tr( "Wrong editing tool, cannot apply the 'capture point' tool on this vector layer" ), QgsMessageBar::WARNING ); return; } QgsPoint savePoint; //point in layer coordinates try { QgsPointV2 fetchPoint; int res; res = fetchLayerPoint( e->mapPointMatch(), fetchPoint ); if ( res == 0 ) { savePoint = QgsPoint( fetchPoint.x(), fetchPoint.y() ); } else { savePoint = toLayerCoordinates( vlayer, e->mapPoint() ); } QgsDebugMsg( "savePoint = " + savePoint.toString() ); } catch ( QgsCsException &cse ) { Q_UNUSED( cse ); emit messageEmitted( tr( "Cannot transform the point to the layers coordinate system" ), QgsMessageBar::WARNING ); return; } //only do the rest for provider with feature addition support //note that for the grass provider, this will return false since //grass provider has its own mechanism of feature addition if ( provider->capabilities() & QgsVectorDataProvider::AddFeatures ) { QgsFeature f( vlayer->fields(), 0 ); QgsGeometry g; if ( layerWKBType == QgsWkbTypes::Point ) { g = QgsGeometry::fromPoint( savePoint ); } else if ( layerWKBType == QgsWkbTypes::Point25D ) { g = QgsGeometry( new QgsPointV2( QgsWkbTypes::PointZ, savePoint.x(), savePoint.y(), 0.0 ) ); } else if ( layerWKBType == QgsWkbTypes::MultiPoint ) { g = QgsGeometry::fromMultiPoint( QgsMultiPoint() << savePoint ); } else if ( layerWKBType == QgsWkbTypes::MultiPoint25D ) { QgsMultiPointV2* mp = new QgsMultiPointV2(); mp->addGeometry( new QgsPointV2( QgsWkbTypes::PointZ, savePoint.x(), savePoint.y(), 0.0 ) ); g = QgsGeometry( mp ); } else { // if layer supports more types (mCheckGeometryType is false) g = QgsGeometry::fromPoint( savePoint ); } f.setGeometry( g ); f.setValid( true ); addFeature( vlayer, &f, false ); vlayer->triggerRepaint(); } } // LINE AND POLYGON CAPTURING else if ( mode() == CaptureLine || mode() == CapturePolygon ) { //check we only use the line tool for line/multiline layers if ( mode() == CaptureLine && vlayer->geometryType() != QgsWkbTypes::LineGeometry && mCheckGeometryType ) { emit messageEmitted( tr( "Wrong editing tool, cannot apply the 'capture line' tool on this vector layer" ), QgsMessageBar::WARNING ); return; } //check we only use the polygon tool for polygon/multipolygon layers if ( mode() == CapturePolygon && vlayer->geometryType() != QgsWkbTypes::PolygonGeometry && mCheckGeometryType ) { emit messageEmitted( tr( "Wrong editing tool, cannot apply the 'capture polygon' tool on this vector layer" ), QgsMessageBar::WARNING ); return; } //add point to list and to rubber band if ( e->button() == Qt::LeftButton ) { int error = addVertex( e->mapPoint(), e->mapPointMatch() ); if ( error == 1 ) { //current layer is not a vector layer return; } else if ( error == 2 ) { //problem with coordinate transformation emit messageEmitted( tr( "Cannot transform the point to the layers coordinate system" ), QgsMessageBar::WARNING ); return; } startCapturing(); } else if ( e->button() == Qt::RightButton ) { // End of string deleteTempRubberBand(); //lines: bail out if there are not at least two vertices if ( mode() == CaptureLine && size() < 2 ) { stopCapturing(); return; } //polygons: bail out if there are not at least two vertices if ( mode() == CapturePolygon && size() < 3 ) { stopCapturing(); return; } if ( mode() == CapturePolygon ) { closePolygon(); } //create QgsFeature with wkb representation QScopedPointer< QgsFeature > f( new QgsFeature( vlayer->fields(), 0 ) ); //does compoundcurve contain circular strings? //does provider support circular strings? bool hasCurvedSegments = captureCurve()->hasCurvedSegments(); bool providerSupportsCurvedSegments = vlayer->dataProvider()->capabilities() & QgsVectorDataProvider::CircularGeometries; QgsCurve* curveToAdd = nullptr; if ( hasCurvedSegments && providerSupportsCurvedSegments ) { curveToAdd = captureCurve()->clone(); } else { curveToAdd = captureCurve()->curveToLine(); } if ( mode() == CaptureLine ) { QgsGeometry* g = new QgsGeometry( curveToAdd ); f->setGeometry( *g ); delete g; } else { QgsCurvePolygon* poly = nullptr; if ( hasCurvedSegments && providerSupportsCurvedSegments ) { poly = new QgsCurvePolygon(); } else { poly = new QgsPolygonV2(); } poly->setExteriorRing( curveToAdd ); QgsGeometry* g = new QgsGeometry( poly ); f->setGeometry( *g ); delete g; QgsGeometry featGeom = f->geometry(); int avoidIntersectionsReturn = featGeom.avoidIntersections(); f->setGeometry( featGeom ); if ( avoidIntersectionsReturn == 1 ) { //not a polygon type. Impossible to get there } if ( f->geometry().isGeosEmpty() ) //avoid intersection might have removed the whole geometry { emit messageEmitted( tr( "The feature cannot be added because it's geometry collapsed due to intersection avoidance" ), QgsMessageBar::CRITICAL ); stopCapturing(); return; } } f->setValid( true ); if ( addFeature( vlayer, f.data(), false ) ) { //add points to other features to keep topology up-to-date int topologicalEditing = QgsProject::instance()->readNumEntry( "Digitizing", "/TopologicalEditing", 0 ); //use always topological editing for avoidIntersection. //Otherwise, no way to guarantee the geometries don't have a small gap in between. QStringList intersectionLayers = QgsProject::instance()->readListEntry( "Digitizing", "/AvoidIntersectionsList" ); bool avoidIntersection = !intersectionLayers.isEmpty(); if ( avoidIntersection ) //try to add topological points also to background layers { QStringList::const_iterator lIt = intersectionLayers.constBegin(); for ( ; lIt != intersectionLayers.constEnd(); ++lIt ) { QgsMapLayer* ml = QgsMapLayerRegistry::instance()->mapLayer( *lIt ); QgsVectorLayer* vl = qobject_cast<QgsVectorLayer*>( ml ); //can only add topological points if background layer is editable... if ( vl && vl->geometryType() == QgsWkbTypes::PolygonGeometry && vl->isEditable() ) { vl->addTopologicalPoints( f->geometry() ); } } } else if ( topologicalEditing ) { vlayer->addTopologicalPoints( f->geometry() ); } } stopCapturing(); } } }
QgsPointV2 QgsMapTool::toMapCoordinates( QgsMapLayer* layer, const QgsPointV2& point ) { QgsPoint result = mCanvas->mapSettings().layerToMapCoordinates( layer, QgsPoint( point.x(), point.y() ) ); return QgsPointV2( result.x(), result.y() ); }
void QgsFeatureRendererV2::renderFeatureWithSymbol( QgsFeature& feature, QgsSymbolV2* symbol, QgsRenderContext& context, int layer, bool selected, bool drawVertexMarker ) { QgsSymbolV2::SymbolType symbolType = symbol->type(); const QgsGeometry* geom = feature.constGeometry(); if ( !geom || !geom->geometry() ) { return; } const QgsGeometry* segmentizedGeometry = geom; bool deleteSegmentizedGeometry = false; context.setGeometry( geom->geometry() ); //convert curve types to normal point/line/polygon ones switch ( QgsWKBTypes::flatType( geom->geometry()->wkbType() ) ) { case QgsWKBTypes::CurvePolygon: case QgsWKBTypes::CircularString: case QgsWKBTypes::CompoundCurve: case QgsWKBTypes::MultiSurface: case QgsWKBTypes::MultiCurve: { QgsAbstractGeometryV2* g = geom->geometry()->segmentize(); if ( !g ) { return; } segmentizedGeometry = new QgsGeometry( g ); deleteSegmentizedGeometry = true; break; } default: break; } switch ( QgsWKBTypes::flatType( segmentizedGeometry->geometry()->wkbType() ) ) { case QgsWKBTypes::Point: { if ( symbolType != QgsSymbolV2::Marker ) { QgsDebugMsg( "point can be drawn only with marker symbol!" ); break; } QPointF pt; _getPoint( pt, context, segmentizedGeometry->asWkb() ); (( QgsMarkerSymbolV2* )symbol )->renderPoint( pt, &feature, context, layer, selected ); if ( context.testFlag( QgsRenderContext::DrawSymbolBounds ) ) { //draw debugging rect context.painter()->setPen( Qt::red ); context.painter()->setBrush( QColor( 255, 0, 0, 100 ) ); context.painter()->drawRect((( QgsMarkerSymbolV2* )symbol )->bounds( pt, context ) ); } } break; case QgsWKBTypes::LineString: { if ( symbolType != QgsSymbolV2::Line ) { QgsDebugMsg( "linestring can be drawn only with line symbol!" ); break; } QPolygonF pts; _getLineString( pts, context, segmentizedGeometry->asWkb(), symbol->clipFeaturesToExtent() ); (( QgsLineSymbolV2* )symbol )->renderPolyline( pts, &feature, context, layer, selected ); } break; case QgsWKBTypes::Polygon: { if ( symbolType != QgsSymbolV2::Fill ) { QgsDebugMsg( "polygon can be drawn only with fill symbol!" ); break; } QPolygonF pts; QList<QPolygonF> holes; _getPolygon( pts, holes, context, segmentizedGeometry->asWkb(), symbol->clipFeaturesToExtent() ); (( QgsFillSymbolV2* )symbol )->renderPolygon( pts, ( holes.count() ? &holes : NULL ), &feature, context, layer, selected ); } break; case QgsWKBTypes::MultiPoint: { if ( symbolType != QgsSymbolV2::Marker ) { QgsDebugMsg( "multi-point can be drawn only with marker symbol!" ); break; } QgsConstWkbPtr wkbPtr( segmentizedGeometry->asWkb() + 1 + sizeof( int ) ); unsigned int num; wkbPtr >> num; const unsigned char* ptr = wkbPtr; QPointF pt; for ( unsigned int i = 0; i < num; ++i ) { ptr = QgsConstWkbPtr( _getPoint( pt, context, ptr ) ); (( QgsMarkerSymbolV2* )symbol )->renderPoint( pt, &feature, context, layer, selected ); } } break; case QgsWKBTypes::MultiCurve: case QgsWKBTypes::MultiLineString: { if ( symbolType != QgsSymbolV2::Line ) { QgsDebugMsg( "multi-linestring can be drawn only with line symbol!" ); break; } QgsConstWkbPtr wkbPtr( segmentizedGeometry->asWkb() + 1 + sizeof( int ) ); unsigned int num; wkbPtr >> num; const unsigned char* ptr = wkbPtr; QPolygonF pts; const QgsGeometryCollectionV2* geomCollection = dynamic_cast<const QgsGeometryCollectionV2*>( geom->geometry() ); for ( unsigned int i = 0; i < num; ++i ) { if ( geomCollection ) { context.setGeometry( geomCollection->geometryN( i ) ); } ptr = QgsConstWkbPtr( _getLineString( pts, context, ptr, symbol->clipFeaturesToExtent() ) ); (( QgsLineSymbolV2* )symbol )->renderPolyline( pts, &feature, context, layer, selected ); } } break; case QgsWKBTypes::MultiSurface: case QgsWKBTypes::MultiPolygon: { if ( symbolType != QgsSymbolV2::Fill ) { QgsDebugMsg( "multi-polygon can be drawn only with fill symbol!" ); break; } QgsConstWkbPtr wkbPtr( segmentizedGeometry->asWkb() + 1 + sizeof( int ) ); unsigned int num; wkbPtr >> num; const unsigned char* ptr = wkbPtr; QPolygonF pts; QList<QPolygonF> holes; const QgsGeometryCollectionV2* geomCollection = dynamic_cast<const QgsGeometryCollectionV2*>( geom->geometry() ); for ( unsigned int i = 0; i < num; ++i ) { if ( geomCollection ) { context.setGeometry( geomCollection->geometryN( i ) ); } ptr = _getPolygon( pts, holes, context, ptr, symbol->clipFeaturesToExtent() ); (( QgsFillSymbolV2* )symbol )->renderPolygon( pts, ( holes.count() ? &holes : NULL ), &feature, context, layer, selected ); } break; } default: QgsDebugMsg( QString( "feature %1: unsupported wkb type 0x%2 for rendering" ).arg( feature.id() ).arg( geom->wkbType(), 0, 16 ) ); } if ( drawVertexMarker ) { const QgsCoordinateTransform* ct = context.coordinateTransform(); const QgsMapToPixel& mtp = context.mapToPixel(); QgsPointV2 vertexPoint; QgsVertexId vertexId; double x, y, z; QPointF mapPoint; while ( geom->geometry()->nextVertex( vertexId, vertexPoint ) ) { //transform x = vertexPoint.x(); y = vertexPoint.y(); z = vertexPoint.z(); if ( ct ) { ct->transformInPlace( x, y, z ); } mapPoint.setX( x ); mapPoint.setY( y ); mtp.transformInPlace( mapPoint.rx(), mapPoint.ry() ); renderVertexMarker( mapPoint, context ); } } if ( deleteSegmentizedGeometry ) { delete segmentizedGeometry; } }
void QgsGeometryUtils::circleCenterRadius( const QgsPointV2& pt1, const QgsPointV2& pt2, const QgsPointV2& pt3, double& radius, double& centerX, double& centerY ) { double temp, bc, cd, det; //closed circle if ( qgsDoubleNear( pt1.x(), pt3.x() ) && qgsDoubleNear( pt1.y(), pt3.y() ) ) { centerX = pt2.x(); centerY = pt2.y(); radius = sqrt( pow( pt2.x() - pt1.x(), 2.0 ) + pow( pt2.y() - pt1.y(), 2.0 ) ); return; } temp = pt2.x() * pt2.x() + pt2.y() * pt2.y(); bc = ( pt1.x() * pt1.x() + pt1.y() * pt1.y() - temp ) / 2.0; cd = ( temp - pt3.x() * pt3.x() - pt3.y() * pt3.y() ) / 2.0; det = ( pt1.x() - pt2.x() ) * ( pt2.y() - pt3.y() ) - ( pt2.x() - pt3.x() ) * ( pt1.y() - pt2.y() ); /* Check colinearity */ if ( qgsDoubleNear( fabs( det ), 0.0 ) ) { radius = -1.0; return; } det = 1.0 / det; centerX = ( bc * ( pt2.y() - pt3.y() ) - cd * ( pt1.y() - pt2.y() ) ) * det; centerY = (( pt1.x() - pt2.x() ) * cd - ( pt2.x() - pt3.x() ) * bc ) * det; radius = sqrt(( centerX - pt1.x() ) * ( centerX - pt1.x() ) + ( centerY - pt1.y() ) * ( centerY - pt1.y() ) ); }
void QgsMarkerLineSymbolLayerV2::renderPolylineVertex( const QPolygonF& points, QgsSymbolV2RenderContext& context, Placement placement ) { if ( points.isEmpty() ) return; QgsRenderContext& rc = context.renderContext(); double origAngle = mMarker->angle(); int i, maxCount; bool isRing = false; double offsetAlongLine = mOffsetAlongLine; if ( hasDataDefinedProperty( QgsSymbolLayerV2::EXPR_OFFSET_ALONG_LINE ) ) { context.setOriginalValueVariable( mOffsetAlongLine ); offsetAlongLine = evaluateDataDefinedProperty( QgsSymbolLayerV2::EXPR_OFFSET_ALONG_LINE, context, mOffsetAlongLine ).toDouble(); } if ( offsetAlongLine != 0 ) { //scale offset along line offsetAlongLine = QgsSymbolLayerV2Utils::convertToPainterUnits( rc, offsetAlongLine, mOffsetAlongLineUnit, mOffsetAlongLineMapUnitScale ); } if ( offsetAlongLine == 0 && context.renderContext().geometry() && context.renderContext().geometry()->hasCurvedSegments() && ( placement == Vertex || placement == CurvePoint ) ) { const QgsCoordinateTransform* ct = context.renderContext().coordinateTransform(); const QgsMapToPixel& mtp = context.renderContext().mapToPixel(); QgsVertexId vId; QgsPointV2 vPoint; double x, y, z; QPointF mapPoint; while ( context.renderContext().geometry()->nextVertex( vId, vPoint ) ) { if (( placement == Vertex && vId.type == QgsVertexId::SegmentVertex ) || ( placement == CurvePoint && vId.type == QgsVertexId::CurveVertex ) ) { //transform x = vPoint.x(), y = vPoint.y(); z = vPoint.z(); if ( ct ) { ct->transformInPlace( x, y, z ); } mapPoint.setX( x ); mapPoint.setY( y ); mtp.transformInPlace( mapPoint.rx(), mapPoint.ry() ); if ( mRotateMarker ) { double angle = context.renderContext().geometry()->vertexAngle( vId ); mMarker->setAngle( angle * 180 / M_PI ); } mMarker->renderPoint( mapPoint, context.feature(), rc, -1, context.selected() ); } } return; } if ( placement == FirstVertex ) { i = 0; maxCount = 1; } else if ( placement == LastVertex ) { i = points.count() - 1; maxCount = points.count(); } else if ( placement == Vertex ) { i = 0; maxCount = points.count(); if ( points.first() == points.last() ) isRing = true; } else { return; } if ( offsetAlongLine > 0 && ( placement == FirstVertex || placement == LastVertex ) ) { double distance; distance = placement == FirstVertex ? offsetAlongLine : -offsetAlongLine; renderOffsetVertexAlongLine( points, i, distance, context ); // restore original rotation mMarker->setAngle( origAngle ); return; } for ( ; i < maxCount; ++i ) { if ( isRing && placement == Vertex && i == points.count() - 1 ) { continue; // don't draw the last marker - it has been drawn already } // rotate marker (if desired) if ( mRotateMarker ) { double angle = markerAngle( points, isRing, i ); mMarker->setAngle( origAngle + angle * 180 / M_PI ); } mMarker->renderPoint( points.at( i ), context.feature(), rc, -1, context.selected() ); } // restore original rotation mMarker->setAngle( origAngle ); }
void QgsGeometrySegmentLengthCheck::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 featureGeom = feature.geometry(); QgsAbstractGeometry* geom = featureGeom.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 ); if ( nVerts < 2 ) { continue; } for ( int iVert = 0, jVert = nVerts - 1; iVert < nVerts; jVert = iVert++ ) { QgsPointV2 pi = geom->vertexAt( QgsVertexId( iPart, iRing, iVert ) ); QgsPointV2 pj = geom->vertexAt( QgsVertexId( iPart, iRing, jVert ) ); double dist = qSqrt( QgsGeometryUtils::sqrDistance2D( pi, pj ) ); if ( dist < mMinLength ) { errors.append( new QgsGeometryCheckError( this, featureid, QgsPointV2( 0.5 * ( pi.x() + pj.x() ), 0.5 * ( pi.y() + pj.y() ) ), QgsVertexId( iPart, iRing, iVert ), dist, QgsGeometryCheckError::ValueLength ) ); } } } } } }
void QgsCircularString::segmentize( const QgsPointV2& p1, const QgsPointV2& p2, const QgsPointV2& p3, QgsPointSequence &points, double tolerance, SegmentationToleranceType toleranceType ) const { //adapted code from postgis double radius = 0; double centerX = 0; double centerY = 0; QgsGeometryUtils::circleCenterRadius( p1, p2, p3, radius, centerX, centerY ); int segSide = segmentSide( p1, p3, p2 ); if ( p1 != p3 && ( radius < 0 || qgsDoubleNear( segSide, 0.0 ) ) ) //points are colinear { points.append( p1 ); points.append( p2 ); points.append( p3 ); return; } bool clockwise = false; if ( segSide == -1 ) { clockwise = true; } double increment = tolerance; //one segment per degree if ( toleranceType == QgsAbstractGeometry::MaximumDifference ) { double halfAngle = acos( -tolerance / radius + 1 ); increment = 2 * halfAngle; } //angles of pt1, pt2, pt3 double a1 = atan2( p1.y() - centerY, p1.x() - centerX ); double a2 = atan2( p2.y() - centerY, p2.x() - centerX ); double a3 = atan2( p3.y() - centerY, p3.x() - centerX ); if ( clockwise ) { increment *= -1; /* Adjust a3 down so we can decrement from a1 to a3 cleanly */ if ( a3 >= a1 ) a3 -= 2.0 * M_PI; if ( a2 > a1 ) a2 -= 2.0 * M_PI; } else { /* Adjust a3 up so we can increment from a1 to a3 cleanly */ if ( a3 <= a1 ) a3 += 2.0 * M_PI; if ( a2 < a1 ) a2 += 2.0 * M_PI; } bool hasZ = is3D(); bool hasM = isMeasure(); double x, y; double z = 0; double m = 0; points.append( p1 ); if ( p2 != p3 && p1 != p2 ) //draw straight line segment if two points have the same position { QgsWkbTypes::Type pointWkbType = QgsWkbTypes::Point; if ( hasZ ) pointWkbType = QgsWkbTypes::addZ( pointWkbType ); if ( hasM ) pointWkbType = QgsWkbTypes::addM( pointWkbType ); //make sure the curve point p2 is part of the segmentized vertices. But only if p1 != p3 bool addP2 = true; if ( qgsDoubleNear( p1.x(), p3.x() ) && qgsDoubleNear( p1.y(), p3.y() ) ) { addP2 = false; } for ( double angle = a1 + increment; clockwise ? angle > a3 : angle < a3; angle += increment ) { if (( addP2 && clockwise && angle < a2 ) || ( addP2 && !clockwise && angle > a2 ) ) { points.append( p2 ); addP2 = false; } x = centerX + radius * cos( angle ); y = centerY + radius * sin( angle ); if ( !hasZ && !hasM ) { points.append( QgsPointV2( x, y ) ); continue; } if ( hasZ ) { z = interpolateArc( angle, a1, a2, a3, p1.z(), p2.z(), p3.z() ); } if ( hasM ) { m = interpolateArc( angle, a1, a2, a3, p1.m(), p2.m(), p3.m() ); } points.append( QgsPointV2( pointWkbType, x, y, z, m ) ); } } points.append( p3 ); }
void QgsMapToolIdentify::closestVertexAttributes( const QgsAbstractGeometryV2& geometry, QgsVertexId vId, QgsMapLayer *layer, QMap< QString, QString >& derivedAttributes ) { QString str = QLocale::system().toString( vId.vertex + 1 ); derivedAttributes.insert( tr( "Closest vertex number" ), str ); QgsPointV2 closestPoint = geometry.vertexAt( vId ); QgsPoint closestPointMapCoords = mCanvas->mapSettings().layerToMapCoordinates( layer, QgsPoint( closestPoint.x(), closestPoint.y() ) ); str = QLocale::system().toString( closestPointMapCoords.x(), 'g', 10 ); derivedAttributes.insert( "Closest vertex X", str ); str = QLocale::system().toString( closestPointMapCoords.y(), 'g', 10 ); derivedAttributes.insert( "Closest vertex Y", str ); if ( closestPoint.is3D() ) { str = QLocale::system().toString( closestPoint.z(), 'g', 10 ); derivedAttributes.insert( "Closest vertex Z", str ); } if ( closestPoint.isMeasure() ) { str = QLocale::system().toString( closestPoint.m(), 'g', 10 ); derivedAttributes.insert( "Closest vertex M", str ); } }
bool QgsTriangle::validateGeom( const QgsPointV2 &p1, const QgsPointV2 &p2, const QgsPointV2 &p3 ) { if ( ( ( p1 == p2 ) || ( p1 == p3 ) || ( p2 == p3 ) ) || qgsDoubleNear( QgsGeometryUtils::leftOfLine( p1.x(), p1.y(), p2.x(), p2.y(), p3.x(), p3.y() ), 0.0 ) ) { return false; } return true; }