Exemplo n.º 1
0
void CanvasCairo::pathAltArcTo(float rx, float ry, float angle, bool largeArc, bool sweep, float x, float y) {
	double _x, _y;
	cairo_get_current_point (_context, &_x, &_y);

	rx = fabsf(rx); ry = fabsf(ry);

	Mat4 transform(Mat4::IDENTITY); Mat4::createRotationZ(angle, &transform);
	Mat4 inverse = transform; inverse.transpose();

	Vec2 vDash(cocos2d::PointApplyTransform(Vec2((_x - x) / 2, (_y - y) / 2), inverse));
	float lambda = (vDash.x * vDash.x) / (rx * rx) + (vDash.y * vDash.y) / (ry * ry);
	if (lambda > 1.0f) {
		rx = sqrtf(lambda) * rx; ry = sqrtf(lambda) * ry;
		vDash = Vec2(cocos2d::PointApplyTransform(Vec2((_x - x) / 2, (_y - y) / 2), inverse));
	}

	float rx_y1_ = (rx * rx * vDash.y * vDash.y);
	float ry_x1_ = (ry * ry * vDash.x * vDash.x);
	float cst = sqrtf(((rx * rx * ry * ry) - rx_y1_ - ry_x1_) / (rx_y1_ + ry_x1_));

	Vec2 cDash((largeArc != sweep ? 1.0f : -1.0f) * cst * rx * vDash.y / ry,
			(largeArc != sweep ? 1.0f : -1.0f) * - cst * ry * vDash.x / rx);

	float cx = cDash.x + (_x + x) / 2;
	float cy = cDash.y + (_y + y) / 2;

	float startAngle = Vec2::angle(Vec2(1.0f, 0.0f), Vec2((vDash.x - cDash.x) / rx, (vDash.y - cDash.y) / ry));
	float sweepAngle = Vec2::angle(Vec2((vDash.x - cDash.x) / rx, (vDash.y - cDash.y) / ry),
			Vec2((-vDash.x - cDash.x) / rx, (-vDash.y - cDash.y) / ry));

	pathArcTo(cx, cy, rx, ry, startAngle, sweepAngle, angle);
}
Exemplo n.º 2
0
// 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 );
  }
}
Exemplo n.º 3
0
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 );
}