bool QgsCurve::isClosed() const { if ( numPoints() == 0 ) return false; //don't consider M-coordinates when testing closedness QgsPointV2 start = startPoint(); QgsPointV2 end = endPoint(); return ( qgsDoubleNear( start.x(), end.x(), 1E-8 ) && qgsDoubleNear( start.y(), end.y(), 1E-8 ) && qgsDoubleNear( start.z(), end.z(), 1E-8 ) ); }
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 ) ); } }
bool QgsLineStringV2::insertVertex( const QgsVertexId& position, const QgsPointV2& vertex ) { if ( position.vertex < 0 || position.vertex > mX.size() ) { return false; } if ( mWkbType == QgsWKBTypes::Unknown || mX.isEmpty() ) { setZMTypeFromSubGeometry( &vertex, QgsWKBTypes::LineString ); } mX.insert( position.vertex, vertex.x() ); mY.insert( position.vertex, vertex.y() ); if ( is3D() ) { mZ.insert( position.vertex, vertex.z() ); } if ( isMeasure() ) { mM.insert( position.vertex, vertex.m() ); } mBoundingBox = QgsRectangle(); //set bounding box invalid return true; }
bool QgsCircularString::insertVertex( QgsVertexId position, const QgsPointV2 &vertex ) { if ( position.vertex > mX.size() || position.vertex < 1 ) { return false; } mX.insert( position.vertex, vertex.x() ); mY.insert( position.vertex, vertex.y() ); if ( is3D() ) { mZ.insert( position.vertex, vertex.z() ); } if ( isMeasure() ) { mM.insert( position.vertex, vertex.m() ); } bool vertexNrEven = ( position.vertex % 2 == 0 ); if ( vertexNrEven ) { insertVertexBetween( position.vertex - 2, position.vertex - 1, position.vertex ); } else { insertVertexBetween( position.vertex, position.vertex + 1, position.vertex - 1 ); } clearCache(); //set bounding box invalid return true; }
/** * Calculate the area of a triangle in 3d space */ static double triarea3d( const QgsPointV2 &P1, const QgsPointV2 &P2, const QgsPointV2 &P3 ) { //LWDEBUG( 2, "Entered triarea3d" ); double ax, bx, ay, by, az, bz, cx, cy, cz, area; ax = P1.x() - P2.x(); bx = P3.x() - P2.x(); ay = P1.y() - P2.y(); by = P3.y() - P2.y(); az = P1.z() - P2.z(); bz = P3.z() - P2.z(); cx = ay * bz - az * by; cy = az * bx - ax * bz; cz = ax * by - ay * bx; area = qAbs( 0.5 * ( sqrt( cx * cx + cy * cy + cz * cz ) ) ); return area; }
void QgsLineStringV2::addVertex( const QgsPointV2& pt ) { if ( mWkbType == QgsWKBTypes::Unknown ) { setZMTypeFromSubGeometry( &pt, QgsWKBTypes::LineString ); } mCoords.append( QPointF( pt.x(), pt.y() ) ); if ( is3D() ) { mZ.append( pt.z() ); } if ( isMeasure() ) { mM.append( pt.m() ); } }
bool QgsLineStringV2::insertVertex( const QgsVertexId& position, const QgsPointV2& vertex ) { if ( position.vertex < 0 || position.vertex > mCoords.size() ) { return false; } mCoords.insert( position.vertex, QPointF( vertex.x(), vertex.y() ) ); if ( is3D() ) { mZ.insert( position.vertex, vertex.z() ); } if ( isMeasure() ) { mM.insert( position.vertex, vertex.m() ); } return true; }
void QgsLineStringV2::addVertex( const QgsPointV2& pt ) { if ( mWkbType == QgsWKBTypes::Unknown ) { setZMTypeFromSubGeometry( &pt, QgsWKBTypes::LineString ); } mCoords.append( QPointF( pt.x(), pt.y() ) ); if ( is3D() ) { mZ.append( pt.z() ); } if ( isMeasure() ) { mM.append( pt.m() ); } mBoundingBox = QgsRectangle(); //set bounding box invalid so it needs to be recalculated next time }
bool QgsLineStringV2::insertVertex( const QgsVertexId& position, const QgsPointV2& vertex ) { if ( position.vertex < 0 || position.vertex >= mCoords.size() ) { return false; } mCoords.insert( position.vertex, QPointF( vertex.x(), vertex.y() ) ); if ( is3D() ) { mZ.insert( position.vertex, vertex.z() ); } if ( isMeasure() ) { mM.insert( position.vertex, vertex.m() ); } mBoundingBox = QgsRectangle(); //set bounding box invalid so it needs to be recalculated next time return true; }
void QgsLineStringV2::addVertex( const QgsPointV2& pt ) { if ( mWkbType == QgsWKBTypes::Unknown || mX.isEmpty() ) { setZMTypeFromSubGeometry( &pt, QgsWKBTypes::LineString ); } mX.append( pt.x() ); mY.append( pt.y() ); if ( is3D() ) { mZ.append( pt.z() ); } if ( isMeasure() ) { mM.append( pt.m() ); } mBoundingBox = QgsRectangle(); //set bounding box invalid }
bool QgsLineStringV2::moveVertex( const 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(); } 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 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 ); } }
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 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 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; } }