// Draw a "spiral" arc defined by circle arcs around a center, a start and an end radius void spiralArcTo( QPainterPath& path, const QPointF& center, qreal startAngle, qreal startRadius, qreal endAngle, qreal endRadius, int direction ) { // start point QPointF A = circlePoint( center, startRadius, startAngle ); // end point QPointF B = circlePoint( center, endRadius, endAngle ); // middle points qreal deltaAngle; deltaAngle = endAngle - startAngle; if ( direction * deltaAngle < 0.0 ) deltaAngle = deltaAngle + direction * 2 * M_PI; QPointF I1 = circlePoint( center, 0.75 * startRadius + 0.25 * endRadius, startAngle + 0.25 * deltaAngle ); QPointF I2 = circlePoint( center, 0.50 * startRadius + 0.50 * endRadius, startAngle + 0.50 * deltaAngle ); QPointF I3 = circlePoint( center, 0.25 * startRadius + 0.75 * endRadius, startAngle + 0.75 * deltaAngle ); qreal cRadius; QPointF cCenter; // first circle arc if ( ! pointsToCircle( A, I1, I2, cCenter, cRadius ) ) { // aligned points => draw a straight line path.lineTo( I2 ); } else { // angles in the new circle qreal a1 = atan2( cCenter.y() - A.y(), A.x() - cCenter.x() ); qreal a2 = atan2( cCenter.y() - I2.y(), I2.x() - cCenter.x() ); pathArcTo( path, cCenter, cRadius, a1, a2, direction ); } // second circle arc if ( ! pointsToCircle( I2, I3, B, cCenter, cRadius ) ) { // aligned points => draw a straight line path.lineTo( B ); } else { // angles in the new circle qreal a1 = atan2( cCenter.y() - I2.y(), I2.x() - cCenter.x() ); qreal a2 = atan2( cCenter.y() - B.y(), B.x() - cCenter.x() ); pathArcTo( path, cCenter, cRadius, a1, a2, direction ); } }
/** * Updates the preview points (if necessary) * */ void EFX::updatePreview() { if (m_previewPointArray == NULL) return; int stepCount = 128; int step = 0; float stepSize = (float)(1) / ((float)(stepCount) / (M_PI * 2.0)); float i = 0; float *x = new float; float *y = new float; /* Resize the array to contain stepCount points */ m_previewPointArray->resize(stepCount); if (m_algorithm == KCircleAlgorithmName) { /* Draw a preview of a circle */ for (i = 0; i < (M_PI * 2.0); i += stepSize) { circlePoint(this, i, x, y); m_previewPointArray->setPoint(step++, static_cast<int> (*x), static_cast<int> (*y)); } } else if (m_algorithm == KEightAlgorithmName) { /* Draw a preview of a eight */ for (i = 0; i < (M_PI * 2.0); i += stepSize) { eightPoint(this, i, x, y); m_previewPointArray->setPoint(step++, static_cast<int> (*x), static_cast<int> (*y)); } } else if (m_algorithm == KLineAlgorithmName) { /* Draw a preview of a line */ for (i = 0; i < (M_PI * 2.0); i += stepSize) { linePoint(this, i, x, y); m_previewPointArray->setPoint(step++, static_cast<int> (*x), static_cast<int> (*y)); } } else if (m_algorithm == KDiamondAlgorithmName) { /* Draw a preview of a diamond */ for (i = 0; i < (M_PI * 2.0); i += stepSize) { diamondPoint(this, i, x, y); m_previewPointArray->setPoint(step++, static_cast<int> (*x), static_cast<int> (*y)); } } else if (m_algorithm == KTriangleAlgorithmName) { /* Draw a preview of a triangle */ for (i = 0; i < (M_PI * 2.0); i += stepSize) { trianglePoint(this, i, x, y); m_previewPointArray->setPoint(step++, static_cast<int> (*x), static_cast<int> (*y)); } } else if (m_algorithm == KLissajousAlgorithmName) { /* Draw a preview of a lissajous */ for (i = 0; i < (M_PI * 2.0); i += stepSize) { lissajousPoint(this, i, x, y); m_previewPointArray->setPoint(step++, static_cast<int> (*x), static_cast<int> (*y)); } } else { m_previewPointArray->resize(0); } delete x; delete y; }
QPolygonF curvedArrow( QPointF po, QPointF pm, QPointF pd, qreal startWidth, qreal width, qreal headSize, QgsArrowSymbolLayer::HeadType headType, qreal offset ) { qreal circleRadius; QPointF circleCenter; if ( ! pointsToCircle( po, pm, pd, circleCenter, circleRadius ) || circleRadius > 10000.0 ) { // aligned points => draw a straight arrow return straightArrow( po, pd, startWidth, width, headSize, headType, offset ); } // angles of each point qreal angle_o = clampAngle( atan2( circleCenter.y() - po.y(), po.x() - circleCenter.x() ) ); qreal angle_m = clampAngle( atan2( circleCenter.y() - pm.y(), pm.x() - circleCenter.x() ) ); qreal angle_d = clampAngle( atan2( circleCenter.y() - pd.y(), pd.x() - circleCenter.x() ) ); // arc direction : 1 = counter-clockwise, -1 = clockwise int direction = clampAngle( angle_m - angle_o ) < clampAngle( angle_m - angle_d ) ? 1 : -1; qreal deltaAngle = angle_d - angle_o; if ( direction * deltaAngle < 0.0 ) deltaAngle = deltaAngle + direction * 2 * M_PI; qreal length = euclidian_distance( po, pd ); // for close points and deltaAngle < 180, draw a straight line if ( fabs( deltaAngle ) < M_PI && ((( headType == QgsArrowSymbolLayer::HeadSingle ) && ( length < headSize ) ) || (( headType == QgsArrowSymbolLayer::HeadReversed ) && ( length < headSize ) ) || (( headType == QgsArrowSymbolLayer::HeadDouble ) && ( length < 2*headSize ) ) ) ) { return straightArrow( po, pd, startWidth, width, headSize, headType, offset ); } // ajust coordinates to include offset circleRadius += offset; po = circlePoint( circleCenter, circleRadius, angle_o ); pm = circlePoint( circleCenter, circleRadius, angle_m ); pd = circlePoint( circleCenter, circleRadius, angle_d ); qreal headAngle = direction * atan( headSize / circleRadius ); QPainterPath path; if ( headType == QgsArrowSymbolLayer::HeadDouble ) { // the first head path.moveTo( po ); path.lineTo( circlePoint( circleCenter, circleRadius + direction * headSize, angle_o + headAngle ) ); pathArcTo( path, circleCenter, circleRadius + direction * width / 2, angle_o + headAngle, angle_d - headAngle, direction ); // the second head path.lineTo( circlePoint( circleCenter, circleRadius + direction * headSize, angle_d - headAngle ) ); path.lineTo( pd ); path.lineTo( circlePoint( circleCenter, circleRadius - direction * headSize, angle_d - headAngle ) ); pathArcTo( path, circleCenter, circleRadius - direction * width / 2, angle_d - headAngle, angle_o + headAngle, -direction ); // the end of the first head path.lineTo( circlePoint( circleCenter, circleRadius - direction * headSize, angle_o + headAngle ) ); path.lineTo( po ); } else if ( headType == QgsArrowSymbolLayer::HeadSingle ) { path.moveTo( circlePoint( circleCenter, circleRadius + direction * startWidth / 2, angle_o ) ); spiralArcTo( path, circleCenter, angle_o, circleRadius + direction * startWidth / 2, angle_d - headAngle, circleRadius + direction * width / 2, direction ); // the arrow head path.lineTo( circlePoint( circleCenter, circleRadius + direction * headSize, angle_d - headAngle ) ); path.lineTo( pd ); path.lineTo( circlePoint( circleCenter, circleRadius - direction * headSize, angle_d - headAngle ) ); spiralArcTo( path, circleCenter, angle_d - headAngle, circleRadius - direction * width / 2, angle_o, circleRadius - direction * startWidth / 2, -direction ); path.lineTo( circlePoint( circleCenter, circleRadius + direction * startWidth / 2, angle_o ) ); } else if ( headType == QgsArrowSymbolLayer::HeadReversed ) { path.moveTo( circlePoint( circleCenter, circleRadius + direction * width / 2, angle_o + headAngle ) ); spiralArcTo( path, circleCenter, angle_o + headAngle, circleRadius + direction * width / 2, angle_d, circleRadius + direction * startWidth / 2, direction ); path.lineTo( circlePoint( circleCenter, circleRadius - direction * startWidth / 2, angle_d ) ); spiralArcTo( path, circleCenter, angle_d, circleRadius - direction * startWidth / 2, angle_o + headAngle, circleRadius - direction * width / 2, - direction ); path.lineTo( circlePoint( circleCenter, circleRadius - direction * headSize, angle_o + headAngle ) ); path.lineTo( po ); path.lineTo( circlePoint( circleCenter, circleRadius + direction * headSize, angle_o + headAngle ) ); path.lineTo( circlePoint( circleCenter, circleRadius + direction * width / 2, angle_o + headAngle ) ); } return path.toSubpathPolygons().at( 0 ); }
bool EFX::preview(QVector <QPoint>& polygon) { bool retval = true; int stepCount = 128; int step = 0; qreal stepSize = (qreal)(1) / ((qreal)(stepCount) / (M_PI * 2.0)); qreal i = 0; qreal x = 0; qreal y = 0; /* Resize the array to contain stepCount points */ polygon.resize(stepCount); /* Since algorithm is identified by a string, we don't want to do N string comparisons on each for loop increment. So, it's a bit faster to check the algorithm only once and then do the looping. */ if (m_algorithm == KCircleAlgorithmName) { /* Draw a preview of a circle */ for (step = 0; step < stepCount; step++) { circlePoint(this, i, &x, &y); polygon[step] = QPoint(int(x), int(y)); i += stepSize; } } else if (m_algorithm == KEightAlgorithmName) { /* Draw a preview of a eight */ for (step = 0; step < stepCount; step++) { eightPoint(this, i, &x, &y); polygon[step] = QPoint(int(x), int(y)); i += stepSize; } } else if (m_algorithm == KLineAlgorithmName) { /* Draw a preview of a line */ for (step = 0; step < stepCount; step++) { linePoint(this, i, &x, &y); polygon[step] = QPoint(int(x), int(y)); i += stepSize; } } else if (m_algorithm == KDiamondAlgorithmName) { /* Draw a preview of a diamond */ for (step = 0; step < stepCount; step++) { diamondPoint(this, i, &x, &y); polygon[step] = QPoint(int(x), int(y)); i += stepSize; } } else if (m_algorithm == KTriangleAlgorithmName) { /* Draw a preview of a triangle */ for (step = 0; step < stepCount; step++) { trianglePoint(this, i, &x, &y); polygon[step] = QPoint(int(x), int(y)); i += stepSize; } } else if (m_algorithm == KLissajousAlgorithmName) { /* Draw a preview of a lissajous */ for (step = 0; step < stepCount; step++) { lissajousPoint(this, i, &x, &y); polygon[step] = QPoint(int(x), int(y)); i += stepSize; } } else { polygon.resize(0); retval = false; } return retval; }