double QgsPoint::sqrDistToSegment( double x1, double y1, double x2, double y2, QgsPoint& minDistPoint, double epsilon ) const { double nx, ny; //normal vector nx = y2 - y1; ny = -( x2 - x1 ); double t; t = ( m_x * ny - m_y * nx - x1 * ny + y1 * nx ) / (( x2 - x1 ) * ny - ( y2 - y1 ) * nx ); if ( t < 0.0 ) { minDistPoint.setX( x1 ); minDistPoint.setY( y1 ); } else if ( t > 1.0 ) { minDistPoint.setX( x2 ); minDistPoint.setY( y2 ); } else { minDistPoint.setX( x1 + t *( x2 - x1 ) ); minDistPoint.setY( y1 + t *( y2 - y1 ) ); } double dist = sqrDist( minDistPoint ); //prevent rounding errors if the point is directly on the segment if ( qgsDoubleNear( dist, 0.0, epsilon ) ) { minDistPoint.setX( m_x ); minDistPoint.setY( m_y ); return 0.0; } return dist; }
int QgsItemPositionDialog::position( QgsPoint& point ) const { bool convXSuccess, convYSuccess; double x = mXLineEdit->text().toDouble( &convXSuccess ); double y = mYLineEdit->text().toDouble( &convYSuccess ); if ( !convXSuccess || !convYSuccess ) { return 1; } point.setX( x ); point.setY( y ); return 0; }
void QgsAnnotationItem::_readXml( const QDomDocument& doc, const QDomElement& annotationElem ) { Q_UNUSED( doc ); if ( annotationElem.isNull() ) { return; } QPointF pos; pos.setX( annotationElem.attribute( "canvasPosX", "0" ).toDouble() ); pos.setY( annotationElem.attribute( "canvasPosY", "0" ).toDouble() ); setPos( pos ); QgsPoint mapPos; mapPos.setX( annotationElem.attribute( "mapPosX", "0" ).toDouble() ); mapPos.setY( annotationElem.attribute( "mapPosY", "0" ).toDouble() ); mMapPosition = mapPos; if ( !mMapPositionCrs.readXml( annotationElem ) ) { mMapPositionCrs = mMapCanvas->mapSettings().destinationCrs(); } mFrameBorderWidth = annotationElem.attribute( "frameBorderWidth", "0.5" ).toDouble(); mFrameColor.setNamedColor( annotationElem.attribute( "frameColor", "#000000" ) ); mFrameColor.setAlpha( annotationElem.attribute( "frameColorAlpha", "255" ).toInt() ); mFrameBackgroundColor.setNamedColor( annotationElem.attribute( "frameBackgroundColor" ) ); mFrameBackgroundColor.setAlpha( annotationElem.attribute( "frameBackgroundColorAlpha", "255" ).toInt() ); mFrameSize.setWidth( annotationElem.attribute( "frameWidth", "50" ).toDouble() ); mFrameSize.setHeight( annotationElem.attribute( "frameHeight", "50" ).toDouble() ); mOffsetFromReferencePoint.setX( annotationElem.attribute( "offsetX", "0" ).toDouble() ); mOffsetFromReferencePoint.setY( annotationElem.attribute( "offsetY", "0" ).toDouble() ); mMapPositionFixed = annotationElem.attribute( "mapPositionFixed", "1" ).toInt(); setVisible( annotationElem.attribute( "visible", "1" ).toInt() ); //marker symbol QDomElement symbolElem = annotationElem.firstChildElement( "symbol" ); if ( !symbolElem.isNull() ) { QgsMarkerSymbolV2* symbol = QgsSymbolLayerV2Utils::loadSymbol<QgsMarkerSymbolV2>( symbolElem ); if ( symbol ) { delete mMarkerSymbol; mMarkerSymbol = symbol; } } updateBoundingRect(); updateBalloon(); }
bool QgsGeorefTransform::gdal_transform( const QgsPoint &src, QgsPoint &dst, int dstToSrc ) const { GDALTransformerFunc t = GDALTransformer(); // Fail if no transformer function was returned if ( !t ) return false; // Copy the source coordinate for inplace transform double x = src.x(); double y = src.y(); double z = 0.0; int success; // Call GDAL transform function ( *t )( GDALTransformerArgs(), dstToSrc, 1, &x, &y, &z, &success ); if ( !success ) return false; dst.setX( x ); dst.setY( y ); return true; }
void QgsGrassEdit::snap( QgsPoint & point, double startX, double startY ) { double x = point.x(); double y = point.y(); double thresh = threshold(); // Start double startDist = hypot( x - startX, y - startY ); bool startIn = false; if ( startDist <= thresh ) startIn = true; // Nearest node double nodeX = 0; double nodeY = 0; double nodeDist = 0; bool nodeIn = false; int node = mProvider->findNode( x, y, thresh ); if ( node > 0 ) { mProvider->nodeCoor( node, &nodeX, &nodeY ); nodeDist = hypot( x - nodeX, y - nodeY ); nodeIn = true; } // Choose if (( startIn && !nodeIn ) || ( startIn && nodeIn && startDist < nodeDist ) ) { x = startX; y = startY; } else if (( !startIn && nodeIn ) || ( startIn && nodeIn && startDist > nodeDist ) ) { x = nodeX; y = nodeY; } point.setX( x ); point.setY( y ); }
void QgsLeastSquares::linear( std::vector<QgsPoint> mapCoords, std::vector<QgsPoint> pixelCoords, QgsPoint& origin, double& pixelXSize, double& pixelYSize ) { int n = mapCoords.size(); if ( n < 2 ) { throw std::domain_error( QObject::tr( "Fit to a linear transform requires at least 2 points." ).toLocal8Bit().constData() ); } double sumPx( 0 ), sumPy( 0 ), sumPx2( 0 ), sumPy2( 0 ), sumPxMx( 0 ), sumPyMy( 0 ), sumMx( 0 ), sumMy( 0 ); for ( int i = 0; i < n; ++i ) { sumPx += pixelCoords[i].x(); sumPy += pixelCoords[i].y(); sumPx2 += std::pow( pixelCoords[i].x(), 2 ); sumPy2 += std::pow( pixelCoords[i].y(), 2 ); sumPxMx += pixelCoords[i].x() * mapCoords[i].x(); sumPyMy += pixelCoords[i].y() * mapCoords[i].y(); sumMx += mapCoords[i].x(); sumMy += mapCoords[i].y(); } double deltaX = n * sumPx2 - std::pow( sumPx, 2 ); double deltaY = n * sumPy2 - std::pow( sumPy, 2 ); double aX = ( sumPx2 * sumMx - sumPx * sumPxMx ) / deltaX; double aY = ( sumPy2 * sumMy - sumPy * sumPyMy ) / deltaY; double bX = ( n * sumPxMx - sumPx * sumMx ) / deltaX; double bY = ( n * sumPyMy - sumPy * sumMy ) / deltaY; origin.setX( aX ); origin.setY( aY ); pixelXSize = std::abs( bX ); pixelYSize = std::abs( bY ); }
QgsCircle QgsCircle::from3Points( const QgsPoint &pt1, const QgsPoint &pt2, const QgsPoint &pt3, double epsilon ) { QgsPoint p1, p2, p3; if ( !isPerpendicular( pt1, pt2, pt3, epsilon ) ) { p1 = pt1; p2 = pt2; p3 = pt3; } else if ( !isPerpendicular( pt1, pt3, pt2, epsilon ) ) { p1 = pt1; p2 = pt3; p3 = pt2; } else if ( !isPerpendicular( pt2, pt1, pt3, epsilon ) ) { p1 = pt2; p2 = pt1; p3 = pt3; } else if ( !isPerpendicular( pt2, pt3, pt1, epsilon ) ) { p1 = pt2; p2 = pt3; p3 = pt1; } else if ( !isPerpendicular( pt3, pt2, pt1, epsilon ) ) { p1 = pt3; p2 = pt2; p3 = pt1; } else if ( !isPerpendicular( pt3, pt1, pt2, epsilon ) ) { p1 = pt3; p2 = pt1; p3 = pt2; } else { return QgsCircle(); } QgsPoint center = QgsPoint(); double radius = -0.0; // Paul Bourke's algorithm double yDelta_a = p2.y() - p1.y(); double xDelta_a = p2.x() - p1.x(); double yDelta_b = p3.y() - p2.y(); double xDelta_b = p3.x() - p2.x(); if ( qgsDoubleNear( xDelta_a, 0.0, epsilon ) || qgsDoubleNear( xDelta_b, 0.0, epsilon ) ) { return QgsCircle(); } double aSlope = yDelta_a / xDelta_a; double bSlope = yDelta_b / xDelta_b; if ( ( qAbs( xDelta_a ) <= epsilon ) && ( qAbs( yDelta_b ) <= epsilon ) ) { center.setX( 0.5 * ( p2.x() + p3.x() ) ); center.setY( 0.5 * ( p1.y() + p2.y() ) ); radius = center.distance( pt1 ); return QgsCircle( center, radius ); } if ( qAbs( aSlope - bSlope ) <= epsilon ) { return QgsCircle(); } center.setX( ( aSlope * bSlope * ( p1.y() - p3.y() ) + bSlope * ( p1.x() + p2.x() ) - aSlope * ( p2.x() + p3.x() ) ) / ( 2.0 * ( bSlope - aSlope ) ) ); center.setY( -1.0 * ( center.x() - ( p1.x() + p2.x() ) / 2.0 ) / aSlope + ( p1.y() + p2.y() ) / 2.0 ); radius = center.distance( p1 ); return QgsCircle( center, radius ); }
bool QgsMapToolLabel::rotationPoint( QgsPoint& pos, bool ignoreUpsideDown, bool rotatingUnpinned ) { QVector<QgsPoint> cornerPoints = mCurrentLabelPos.cornerPoints; if ( cornerPoints.size() < 4 ) { return false; } if ( mCurrentLabelPos.upsideDown && !ignoreUpsideDown ) { pos = cornerPoints.at( 2 ); } else { pos = cornerPoints.at( 0 ); } //alignment always center/center and rotation 0 for diagrams if ( mCurrentLabelPos.isDiagram ) { pos.setX( pos.x() + mCurrentLabelPos.labelRect.width() / 2.0 ); pos.setY( pos.y() + mCurrentLabelPos.labelRect.height() / 2.0 ); return true; } //adapt pos depending on data defined alignment QString haliString, valiString; currentAlignment( haliString, valiString ); // rotate unpinned labels (i.e. no hali/vali settings) as if hali/vali was Center/Half if ( rotatingUnpinned ) { haliString = "Center"; valiString = "Half"; } // QFont labelFont = labelFontCurrentFeature(); QFontMetricsF labelFontMetrics( mCurrentLabelPos.labelFont ); // NOTE: this assumes the label corner points comprise a rectangle and that the // CRS supports equidistant measurements to accurately determine hypotenuse QgsPoint cp_0 = cornerPoints.at( 0 ); QgsPoint cp_1 = cornerPoints.at( 1 ); QgsPoint cp_3 = cornerPoints.at( 3 ); // QgsDebugMsg( QString( "cp_0: x=%1, y=%2" ).arg( cp_0.x() ).arg( cp_0.y() ) ); // QgsDebugMsg( QString( "cp_1: x=%1, y=%2" ).arg( cp_1.x() ).arg( cp_1.y() ) ); // QgsDebugMsg( QString( "cp_3: x=%1, y=%2" ).arg( cp_3.x() ).arg( cp_3.y() ) ); double labelSizeX = qSqrt( cp_0.sqrDist( cp_1 ) ); double labelSizeY = qSqrt( cp_0.sqrDist( cp_3 ) ); double xdiff = 0; double ydiff = 0; if ( haliString.compare( "Center", Qt::CaseInsensitive ) == 0 ) { xdiff = labelSizeX / 2.0; } else if ( haliString.compare( "Right", Qt::CaseInsensitive ) == 0 ) { xdiff = labelSizeX; } if ( valiString.compare( "Top", Qt::CaseInsensitive ) == 0 || valiString.compare( "Cap", Qt::CaseInsensitive ) == 0 ) { ydiff = labelSizeY; } else { double descentRatio = 1 / labelFontMetrics.ascent() / labelFontMetrics.height(); if ( valiString.compare( "Base", Qt::CaseInsensitive ) == 0 ) { ydiff = labelSizeY * descentRatio; } else if ( valiString.compare( "Half", Qt::CaseInsensitive ) == 0 ) { ydiff = labelSizeY * 0.5 * ( 1 - descentRatio ); } } double angle = mCurrentLabelPos.rotation; double xd = xdiff * cos( angle ) - ydiff * sin( angle ); double yd = xdiff * sin( angle ) + ydiff * cos( angle ); if ( mCurrentLabelPos.upsideDown && !ignoreUpsideDown ) { pos.setX( pos.x() - xd ); pos.setY( pos.y() - yd ); } else { pos.setX( pos.x() + xd ); pos.setY( pos.y() + yd ); } return true; }
double QgsLineString::closestSegment( const QgsPoint &pt, QgsPoint &segmentPt, QgsVertexId &vertexAfter, int *leftOf, double epsilon ) const { double sqrDist = std::numeric_limits<double>::max(); double leftOfDist = std::numeric_limits<double>::max(); int prevLeftOf = 0; double prevLeftOfX = 0.0; double prevLeftOfY = 0.0; double testDist = 0; double segmentPtX, segmentPtY; if ( leftOf ) *leftOf = 0; 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 ); vertexAfter.part = 0; vertexAfter.ring = 0; vertexAfter.vertex = i; } if ( leftOf && qgsDoubleNear( testDist, sqrDist ) ) { int left = QgsGeometryUtils::leftOfLine( pt.x(), pt.y(), prevX, prevY, currentX, currentY ); // if left equals 0, the test could not be performed (e.g. point in line with segment or on segment) // so don't set leftOf in this case, and hope that there's another segment that's the same distance // where we can perform the check if ( left != 0 ) { if ( qgsDoubleNear( testDist, leftOfDist ) && left != prevLeftOf && prevLeftOf != 0 ) { // we have two possible segments each with equal distance to point, but they disagree // on whether or not the point is to the left of them. // so we test the segments themselves and flip the result. // see https://stackoverflow.com/questions/10583212/elegant-left-of-test-for-polyline *leftOf = -QgsGeometryUtils::leftOfLine( currentX, currentY, prevLeftOfX, prevLeftOfY, prevX, prevY ); } else { *leftOf = left; } prevLeftOf = *leftOf; leftOfDist = testDist; prevLeftOfX = prevX; prevLeftOfY = prevY; } else if ( testDist < leftOfDist ) { *leftOf = left; leftOfDist = testDist; prevLeftOf = 0; } } } return sqrDist; }
bool QgsTransectSample::closestSegmentPoints( const QgsGeometry& g1, const QgsGeometry& g2, double& dist, QgsPoint& pt1, QgsPoint& pt2 ) { QgsWkbTypes::Type t1 = g1.wkbType(); if ( t1 != QgsWkbTypes::LineString && t1 != QgsWkbTypes::LineString25D ) { return false; } QgsWkbTypes::Type t2 = g2.wkbType(); if ( t2 != QgsWkbTypes::LineString && t2 != QgsWkbTypes::LineString25D ) { return false; } QgsPolyline pl1 = g1.asPolyline(); QgsPolyline pl2 = g2.asPolyline(); if ( pl1.size() < 2 || pl2.size() < 2 ) { return false; } QgsPoint p11 = pl1.at( 0 ); QgsPoint p12 = pl1.at( 1 ); QgsPoint p21 = pl2.at( 0 ); QgsPoint p22 = pl2.at( 1 ); double p1x = p11.x(); double p1y = p11.y(); double v1x = p12.x() - p11.x(); double v1y = p12.y() - p11.y(); double p2x = p21.x(); double p2y = p21.y(); double v2x = p22.x() - p21.x(); double v2y = p22.y() - p21.y(); double denominatorU = v2x * v1y - v2y * v1x; double denominatorT = v1x * v2y - v1y * v2x; if ( qgsDoubleNear( denominatorU, 0 ) || qgsDoubleNear( denominatorT, 0 ) ) { //lines are parallel //project all points on the other segment and take the one with the smallest distance QgsPoint minDistPoint1; double d1 = p11.sqrDistToSegment( p21.x(), p21.y(), p22.x(), p22.y(), minDistPoint1 ); QgsPoint minDistPoint2; double d2 = p12.sqrDistToSegment( p21.x(), p21.y(), p22.x(), p22.y(), minDistPoint2 ); QgsPoint minDistPoint3; double d3 = p21.sqrDistToSegment( p11.x(), p11.y(), p12.x(), p12.y(), minDistPoint3 ); QgsPoint minDistPoint4; double d4 = p22.sqrDistToSegment( p11.x(), p11.y(), p12.x(), p12.y(), minDistPoint4 ); if ( d1 <= d2 && d1 <= d3 && d1 <= d4 ) { dist = sqrt( d1 ); pt1 = p11; pt2 = minDistPoint1; return true; } else if ( d2 <= d1 && d2 <= d3 && d2 <= d4 ) { dist = sqrt( d2 ); pt1 = p12; pt2 = minDistPoint2; return true; } else if ( d3 <= d1 && d3 <= d2 && d3 <= d4 ) { dist = sqrt( d3 ); pt1 = p21; pt2 = minDistPoint3; return true; } else { dist = sqrt( d4 ); pt1 = p21; pt2 = minDistPoint4; return true; } } double u = ( p1x * v1y - p1y * v1x - p2x * v1y + p2y * v1x ) / denominatorU; double t = ( p2x * v2y - p2y * v2x - p1x * v2y + p1y * v2x ) / denominatorT; if ( u >= 0 && u <= 1.0 && t >= 0 && t <= 1.0 ) { dist = 0; pt1.setX( p2x + u * v2x ); pt1.setY( p2y + u * v2y ); pt2 = pt1; dist = 0; return true; } if ( t > 1.0 ) { pt1.setX( p12.x() ); pt1.setY( p12.y() ); } else if ( t < 0.0 ) { pt1.setX( p11.x() ); pt1.setY( p11.y() ); } if ( u > 1.0 ) { pt2.setX( p22.x() ); pt2.setY( p22.y() ); } if ( u < 0.0 ) { pt2.setX( p21.x() ); pt2.setY( p21.y() ); } if ( t >= 0.0 && t <= 1.0 ) { //project pt2 onto g1 pt2.sqrDistToSegment( p11.x(), p11.y(), p12.x(), p12.y(), pt1 ); } if ( u >= 0.0 && u <= 1.0 ) { //project pt1 onto g2 pt1.sqrDistToSegment( p21.x(), p21.y(), p22.x(), p22.y(), pt2 ); } dist = sqrt( pt1.sqrDist( pt2 ) ); return true; }
void QgsLabel::renderLabel( QgsRenderContext &renderContext, QgsFeature &feature, bool selected, QgsLabelAttributes *classAttributes ) { Q_UNUSED( classAttributes ); if ( mLabelAttributes->selectedOnly() && !selected ) return; QPen pen; QFont font; QString value; QString text; /* Calc scale (not nice) */ QgsPoint point; point = renderContext.mapToPixel().transform( 0, 0 ); double x1 = point.x(); point = renderContext.mapToPixel().transform( 1000, 0 ); double x2 = point.x(); double scale = ( x2 - x1 ) * 0.001; /* Text */ value = fieldValue( Text, feature ); if ( value.isEmpty() ) { text = mLabelAttributes->text(); } else { text = value; } /* Font */ value = fieldValue( Family, feature ); if ( value.isEmpty() ) { font.setFamily( mLabelAttributes->family() ); } else { font.setFamily( value ); } double size; value = fieldValue( Size, feature ); if ( value.isEmpty() ) { size = mLabelAttributes->size(); } else { size = value.toDouble(); } int sizeType; value = fieldValue( SizeType, feature ); if ( value.isEmpty() ) sizeType = mLabelAttributes->sizeType(); else { value = value.toLower(); if ( value.compare( "mapunits" ) == 0 ) sizeType = QgsLabelAttributes::MapUnits; else sizeType = QgsLabelAttributes::PointUnits; } if ( sizeType == QgsLabelAttributes::MapUnits ) { size *= scale; } else //point units { double sizeMM = size * 0.3527; size = sizeMM * renderContext.scaleFactor(); } //Request font larger (multiplied by rasterScaleFactor) as a workaround for the Qt font bug //and scale the painter down by rasterScaleFactor when drawing the label size *= renderContext.rasterScaleFactor(); if (( int )size <= 0 ) // skip too small labels return; font.setPixelSize( size ); value = fieldValue( Color, feature ); if ( value.isEmpty() ) { pen.setColor( mLabelAttributes->color() ); } else { pen.setColor( QColor( value ) ); } value = fieldValue( Bold, feature ); if ( value.isEmpty() ) { font.setBold( mLabelAttributes->bold() ); } else { font.setBold(( bool ) value.toInt() ); } value = fieldValue( Italic, feature ); if ( value.isEmpty() ) { font.setItalic( mLabelAttributes->italic() ); } else { font.setItalic(( bool ) value.toInt() ); } value = fieldValue( Underline, feature ); if ( value.isEmpty() ) { font.setUnderline( mLabelAttributes->underline() ); } else { font.setUnderline(( bool ) value.toInt() ); } value = fieldValue( StrikeOut, feature ); if ( value.isEmpty() ) { font.setStrikeOut( mLabelAttributes->strikeOut() ); } else { font.setStrikeOut(( bool ) value.toInt() ); } // QgsPoint overridePoint; bool useOverridePoint = false; value = fieldValue( XCoordinate, feature ); if ( !value.isEmpty() ) { overridePoint.setX( value.toDouble() ); useOverridePoint = true; } value = fieldValue( YCoordinate, feature ); if ( !value.isEmpty() ) { overridePoint.setY( value.toDouble() ); useOverridePoint = true; } /* Alignment */ int alignment; QFontMetrics fm( font ); int width, height; if ( mLabelAttributes->multilineEnabled() ) { QStringList texts = text.split( "\n" ); width = 0; for ( int i = 0; i < texts.size(); i++ ) { int w = fm.width( texts[i] ); if ( w > width ) width = w; } height = fm.height() * texts.size(); } else { width = fm.width( text ); height = fm.height(); } int dx = 0; int dy = 0; value = fieldValue( Alignment, feature ); if ( value.isEmpty() ) { alignment = mLabelAttributes->alignment(); } else { value = value.toLower(); alignment = 0; if ( value.contains( "left" ) ) alignment |= Qt::AlignLeft; else if ( value.contains( "right" ) ) alignment |= Qt::AlignRight; else alignment |= Qt::AlignHCenter; if ( value.contains( "bottom" ) ) alignment |= Qt::AlignBottom; else if ( value.contains( "top" ) ) alignment |= Qt::AlignTop; else alignment |= Qt::AlignVCenter; } if ( alignment & Qt::AlignLeft ) { dx = 0; } else if ( alignment & Qt::AlignHCenter ) { dx = -width / 2; } else if ( alignment & Qt::AlignRight ) { dx = -width; } if ( alignment & Qt::AlignBottom ) { dy = 0; } else if ( alignment & Qt::AlignVCenter ) { dy = height / 2; } else if ( alignment & Qt::AlignTop ) { dy = height; } // Offset double xoffset, yoffset; value = fieldValue( XOffset, feature ); if ( value.isEmpty() ) { xoffset = mLabelAttributes->xOffset(); } else { xoffset = value.toDouble(); } value = fieldValue( YOffset, feature ); if ( value.isEmpty() ) { yoffset = mLabelAttributes->yOffset(); } else { yoffset = value.toDouble(); } // recalc offset to pixels if ( mLabelAttributes->offsetType() == QgsLabelAttributes::MapUnits ) { xoffset *= scale; yoffset *= scale; } else { xoffset = xoffset * 0.3527 * renderContext.scaleFactor(); yoffset = yoffset * 0.3527 * renderContext.scaleFactor(); } // Angle double ang; value = fieldValue( Angle, feature ); if ( value.isEmpty() ) { ang = mLabelAttributes->angle(); } else { ang = value.toDouble(); } // Work out a suitable position to put the label for the // feature. For multi-geometries, put the same label on each // part. if ( useOverridePoint ) { renderLabel( renderContext, overridePoint, text, font, pen, dx, dy, xoffset, yoffset, ang, width, height, alignment ); } else { std::vector<labelpoint> points; labelPoint( points, feature ); for ( uint i = 0; i < points.size(); ++i ) { renderLabel( renderContext, points[i].p, text, font, pen, dx, dy, xoffset, yoffset, mLabelAttributes->angleIsAuto() ? points[i].angle : ang, width, height, alignment ); } } }
void QgsGrassEdit::displayIcon( double x, double y, const QPen & pen, int type, int size, QPainter *painter ) { QgsPoint point; QPolygon pointArray( 2 ); point.setX( x ); point.setY( y ); point = transformLayerToCanvas( point ); int px = qRound( point.x() ); int py = qRound( point.y() ); int m = ( size - 1 ) / 2; QPainter *myPainter; if ( !painter ) { myPainter = new QPainter(); myPainter->begin( mPixmap ); } else { myPainter = painter; } myPainter->setPen( pen ); switch ( type ) { case QgsVertexMarker::ICON_CROSS : pointArray.setPoint( 0, px - m, py ); pointArray.setPoint( 1, px + m, py ); myPainter->drawPolyline( pointArray ); pointArray.setPoint( 0, px, py + m ); pointArray.setPoint( 1, px, py - m ); myPainter->drawPolyline( pointArray ); break; case QgsVertexMarker::ICON_X : pointArray.setPoint( 0, px - m, py + m ); pointArray.setPoint( 1, px + m, py - m ); myPainter->drawPolyline( pointArray ); pointArray.setPoint( 0, px - m, py - m ); pointArray.setPoint( 1, px + m, py + m ); myPainter->drawPolyline( pointArray ); break; case QgsVertexMarker::ICON_BOX : pointArray.resize( 5 ); pointArray.setPoint( 0, px - m, py - m ); pointArray.setPoint( 1, px + m, py - m ); pointArray.setPoint( 2, px + m, py + m ); pointArray.setPoint( 3, px - m, py + m ); pointArray.setPoint( 4, px - m, py - m ); myPainter->drawPolyline( pointArray ); break; } if ( !painter ) { myPainter->end(); //mCanvas->update(); mCanvasEdit->update(); delete myPainter; } }
void QgsGeometryAnalyzer::locateAlongSegment( double x1, double y1, double m1, double x2, double y2, double m2, double measure, bool& pt1Ok, QgsPoint& pt1, bool& pt2Ok, QgsPoint& pt2 ) { bool reversed = false; pt1Ok = false; pt2Ok = false; double tolerance = 0.000001; //work with a small tolerance to catch e.g. locations at endpoints if ( m1 > m2 ) { double tmp = m1; m1 = m2; m2 = tmp; reversed = true; } //segment does not match if (( m1 - measure ) > tolerance || ( measure - m2 ) > tolerance ) { pt1Ok = false; pt2Ok = false; return; } //match with vertex1 if ( qgsDoubleNear( m1, measure, tolerance ) ) { if ( reversed ) { pt2Ok = true; pt2.setX( x2 ); pt2.setY( y2 ); } else { pt1Ok = true; pt1.setX( x1 ); pt1.setY( y1 ); } } //match with vertex2 if ( qgsDoubleNear( m2, measure, tolerance ) ) { if ( reversed ) { pt1Ok = true; pt1.setX( x1 ); pt1.setY( y1 ); } else { pt2Ok = true; pt2.setX( x2 ); pt2.setY( y2 ); } } if ( pt1Ok || pt2Ok ) { return; } //match between the vertices if ( qgsDoubleNear( m1, m2 ) ) { pt1.setX( x1 ); pt1.setY( y1 ); pt1Ok = true; return; } double dist = ( measure - m1 ) / ( m2 - m1 ); if ( reversed ) { dist = 1 - dist; } pt1.setX( x1 + dist * ( x2 - x1 ) ); pt1.setY( y1 + dist * ( y2 - y1 ) ); pt1Ok = true; }
bool QgsGeometryAnalyzer::clipSegmentByRange( double x1, double y1, double m1, double x2, double y2, double m2, double range1, double range2, QgsPoint& pt1, QgsPoint& pt2, bool& secondPointClipped ) { bool reversed = m1 > m2; double tmp; //reverse m1, m2 if necessary (and consequently also x1,x2 / y1, y2) if ( reversed ) { tmp = m1; m1 = m2; m2 = tmp; tmp = x1; x1 = x2; x2 = tmp; tmp = y1; y1 = y2; y2 = tmp; } //reverse range1, range2 if necessary if ( range1 > range2 ) { tmp = range1; range1 = range2; range2 = tmp; } //segment completely outside of range if ( m2 < range1 || m1 > range2 ) { return false; } //segment completely inside of range if ( m2 <= range2 && m1 >= range1 ) { if ( reversed ) { pt1.setX( x2 ); pt1.setY( y2 ); pt2.setX( x1 ); pt2.setY( y1 ); } else { pt1.setX( x1 ); pt1.setY( y1 ); pt2.setX( x2 ); pt2.setY( y2 ); } secondPointClipped = false; return true; } //m1 inside and m2 not if ( m1 >= range1 && m1 <= range2 ) { pt1.setX( x1 ); pt1.setY( y1 ); double dist = ( range2 - m1 ) / ( m2 - m1 ); pt2.setX( x1 + ( x2 - x1 ) * dist ); pt2.setY( y1 + ( y2 - y1 ) * dist ); secondPointClipped = !reversed; } //m2 inside and m1 not if ( m2 >= range1 && m2 <= range2 ) { pt2.setX( x2 ); pt2.setY( y2 ); double dist = ( m2 - range1 ) / ( m2 - m1 ); pt1.setX( x2 - ( x2 - x1 ) * dist ); pt1.setY( y2 - ( y2 - y1 ) * dist ); secondPointClipped = reversed; } //range1 and range 2 both inside the segment if ( range1 >= m1 && range2 <= m2 ) { double dist1 = ( range1 - m1 ) / ( m2 - m1 ); double dist2 = ( range2 - m1 ) / ( m2 - m1 ); pt1.setX( x1 + ( x2 - x1 ) * dist1 ); pt1.setY( y1 + ( y2 - y1 ) * dist1 ); pt2.setX( x1 + ( x2 - x1 ) * dist2 ); pt2.setY( y1 + ( y2 - y1 ) * dist2 ); secondPointClipped = true; } if ( reversed ) //switch p1 and p2 { QgsPoint tmpPt = pt1; pt1 = pt2; pt2 = tmpPt; } return true; }
bool QgsMapToolPinLabels::pinUnpinLabel( QgsVectorLayer* vlayer, const QgsLabelPosition& labelpos, bool pin ) { // skip diagrams if ( labelpos.isDiagram ) { QgsDebugMsg( QString( "Label is diagram, skipping" ) ); return false; } // verify attribute table has x, y fields mapped int xCol, yCol; double xPosOrig, yPosOrig; bool xSuccess, ySuccess; if ( !dataDefinedPosition( vlayer, mCurrentLabelPos.featureId, xPosOrig, xSuccess, yPosOrig, ySuccess, xCol, yCol ) ) { QgsDebugMsg( QString( "Label X or Y column not mapped, skipping" ) ); return false; } // rotation field is optional, but will be used if available, unless data exists int rCol; bool rSuccess = false; double defRot; bool hasRCol = ( layerIsRotatable( vlayer, rCol ) && dataDefinedRotation( vlayer, mCurrentLabelPos.featureId, defRot, rSuccess, true ) ); // get whether to preserve predefined rotation data during label pin/unpin operations bool preserveRot = preserveRotation(); // edit attribute table int fid = labelpos.featureId; bool writeFailed = false; QString labelText = currentLabelText( 24 ); if ( pin ) { // QgsPoint labelpoint = labelpos.cornerPoints.at( 0 ); QgsPoint referencePoint; if ( !rotationPoint( referencePoint, !preserveRot, false ) ) { referencePoint.setX( mCurrentLabelPos.labelRect.xMinimum() ); referencePoint.setY( mCurrentLabelPos.labelRect.yMinimum() ); } double labelX = referencePoint.x(); double labelY = referencePoint.y(); double labelR = labelpos.rotation * 180 / M_PI; // transform back to layer crs, if on-fly on if ( mCanvas->mapSettings().hasCrsTransformEnabled() ) { QgsPoint transformedPoint = mCanvas->mapSettings().mapToLayerCoordinates( vlayer, referencePoint ); labelX = transformedPoint.x(); labelY = transformedPoint.y(); } vlayer->beginEditCommand( tr( "Pinned label" ) + QString( " '%1'" ).arg( labelText ) ); writeFailed = !vlayer->changeAttributeValue( fid, xCol, labelX ); if ( !vlayer->changeAttributeValue( fid, yCol, labelY ) ) writeFailed = true; if ( hasRCol && !preserveRot ) { if ( !vlayer->changeAttributeValue( fid, rCol, labelR ) ) writeFailed = true; } vlayer->endEditCommand(); } else { vlayer->beginEditCommand( tr( "Unpinned label" ) + QString( " '%1'" ).arg( labelText ) ); writeFailed = !vlayer->changeAttributeValue( fid, xCol, QVariant( QString::null ) ); if ( !vlayer->changeAttributeValue( fid, yCol, QVariant( QString::null ) ) ) writeFailed = true; if ( hasRCol && !preserveRot ) { if ( !vlayer->changeAttributeValue( fid, rCol, QVariant( QString::null ) ) ) writeFailed = true; } vlayer->endEditCommand(); } if ( writeFailed ) { QgsDebugMsg( QString( "Write to attribute table failed" ) ); #if 0 QgsDebugMsg( QString( "Undoing and removing failed command from layer's undo stack" ) ); int lastCmdIndx = vlayer->undoStack()->count(); const QgsUndoCommand* lastCmd = qobject_cast<const QgsUndoCommand *>( vlayer->undoStack()->command( lastCmdIndx ) ); if ( lastCmd ) { vlayer->undoEditCommand( lastCmd ); delete vlayer->undoStack()->command( lastCmdIndx ); } #endif return false; } return true; }
bool QgsMapToolLabel::rotationPoint( QgsPoint& pos, bool ignoreUpsideDown ) { QVector<QgsPoint> cornerPoints = mCurrentLabelPos.cornerPoints; if ( cornerPoints.size() < 4 ) { return false; } if ( mCurrentLabelPos.upsideDown && !ignoreUpsideDown ) { pos = mCurrentLabelPos.cornerPoints.at( 2 ); } else { pos = mCurrentLabelPos.cornerPoints.at( 0 ); } //alignment always center/center and rotation 0 for diagrams if ( mCurrentLabelPos.isDiagram ) { pos.setX( pos.x() + mCurrentLabelPos.labelRect.width() / 2.0 ); pos.setY( pos.y() + mCurrentLabelPos.labelRect.height() / 2.0 ); return true; } //adapt pos depending on data defined alignment QString haliString, valiString; currentAlignment( haliString, valiString ); if ( !mCurrentLabelPos.isPinned ) { haliString = "Center"; valiString = "Half"; } QFont labelFont = labelFontCurrentFeature(); QFontMetricsF labelFontMetrics( labelFont ); //label text? QString labelText = currentLabelText(); bool labelSettingsOk; QgsPalLayerSettings& labelSettings = currentLabelSettings( &labelSettingsOk ); if ( !labelSettingsOk ) { return false; } double labelSizeX, labelSizeY; labelSettings.calculateLabelSize( &labelFontMetrics, labelText, labelSizeX, labelSizeY ); double xdiff = 0; double ydiff = 0; if ( haliString.compare( "Center", Qt::CaseInsensitive ) == 0 ) { xdiff = labelSizeX / 2.0; } else if ( haliString.compare( "Right", Qt::CaseInsensitive ) == 0 ) { xdiff = labelSizeX; } if ( valiString.compare( "Top", Qt::CaseInsensitive ) == 0 || valiString.compare( "Cap", Qt::CaseInsensitive ) == 0 ) { ydiff = labelSizeY; } else { double descentRatio = 1 / labelFontMetrics.ascent() / labelFontMetrics.height(); if ( valiString.compare( "Base", Qt::CaseInsensitive ) == 0 ) { ydiff = labelSizeY * descentRatio; } else if ( valiString.compare( "Half", Qt::CaseInsensitive ) == 0 ) { ydiff = labelSizeY * descentRatio; ydiff = labelSizeY * 0.5 * ( 1 - descentRatio ); } } double angle = mCurrentLabelPos.rotation; double xd = xdiff * cos( angle ) - ydiff * sin( angle ); double yd = xdiff * sin( angle ) + ydiff * cos( angle ); if ( mCurrentLabelPos.upsideDown && !ignoreUpsideDown ) { pos.setX( pos.x() - xd ); pos.setY( pos.y() - yd ); } else { pos.setX( pos.x() + xd ); pos.setY( pos.y() + yd ); } return true; }