void on_move(struct bg_point * pos_p) {
#ifndef NDEBUG
    printf("on_move() %d %d %d\n", pos_p->x, pos_p->y, state);
#endif 
    switch (state) {
        case STATE_LINE_WAITING_CLICK_SECOND_POINT:
            bg_undo_restore();
            bg_draw_line(&from, pos_p);
            bg_draw_flush();
            state = STATE_LINE_WAITING_CLICK_SECOND_POINT;
            break;

        case STATE_RECTANGLE_WAITING_CLICK_SECOND_POINT:
            bg_undo_restore();
            bg_draw_rectangle(&from, pos_p);
            bg_draw_flush();
            state = STATE_RECTANGLE_WAITING_CLICK_SECOND_POINT;

        case STATE_POLYLINE_WAITING_CLICK_SUBSEQUENT_POINT:
            bg_undo_restore();
            bg_draw_polyline(&plist, pos_p);
            bg_draw_flush();
            state = STATE_POLYLINE_WAITING_CLICK_SUBSEQUENT_POINT;
            break;

        case STATE_BEZIERCURVE_WAITING_CLICK_SUBSEQUENT_POINT:
            bg_undo_restore();
            bg_draw_line_set_pattern(BG_LINE_PATTERN_3);  /* 切换到虚线 1/8 */
            bg_draw_polyline(&plist, pos_p);  /* 画控制线 */
            bg_draw_line_set_pattern(BG_LINE_PATTERN_0);  /* 切换到实线 */
            bg_draw_beziercurve(&plist, pos_p);
            bg_draw_flush();
            state = STATE_BEZIERCURVE_WAITING_CLICK_SUBSEQUENT_POINT; /* 指向自己的状态转移 */
            break;

        case STATE_CIRCLE_WAITING_CLICK_POINT_ON_CIRCLE:
            bg_undo_restore();
            bg_draw_circle(  /* 画圆 */
                    &center_point, 
                    euclidian_distance(center_point, *pos_p));
            bg_draw_line_set_pattern(BG_LINE_PATTERN_3);  /* 切换到虚线 1/8 */
            bg_draw_line(&center_point, pos_p);
            bg_draw_line_set_pattern(BG_LINE_PATTERN_0);  /* 切换到实线 */
            bg_draw_flush();
            /* state 不变 */
            break;
    }
    return;
}
Example #2
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 );
}
Example #3
0
QPolygonF straightArrow( QPointF po, QPointF pd, qreal startWidth, qreal width, qreal headSize, QgsArrowSymbolLayer::HeadType headType, qreal offset )
{
  QPolygonF polygon; // implicitly shared
  // vector length
  qreal length = euclidian_distance( po, pd );

  // shift points if there is not enough room for the head(s)
  if (( headType == QgsArrowSymbolLayer::HeadSingle ) && ( length < headSize ) )
  {
    po = pd - ( pd - po ) / length * headSize;
    length = headSize;
  }
  else if (( headType == QgsArrowSymbolLayer::HeadReversed ) && ( length < headSize ) )
  {
    pd = po + ( pd - po ) / length * headSize;
    length = headSize;
  }
  else if (( headType == QgsArrowSymbolLayer::HeadDouble ) && ( length < 2 * headSize ) )
  {
    QPointF v = ( pd - po ) / length * headSize;
    QPointF npo = ( po + pd ) / 2.0 - v;
    QPointF npd = ( po + pd ) / 2.0 + v;
    po = npo;
    pd = npd;
    length = 2 * headSize;
  }

  qreal bodyLength = length - headSize;

  // unit vector
  QPointF unitVec = ( pd - po ) / length;
  // perpendicular vector
  QPointF perpVec( -unitVec.y(), unitVec.x() );

  // set offset
  po += perpVec * offset;
  pd += perpVec * offset;

  if ( headType == QgsArrowSymbolLayer::HeadDouble )
  {
    // first head
    polygon << po;
    polygon << po + unitVec * headSize + perpVec * headSize;
    polygon << po + unitVec * headSize + perpVec * ( width * 0.5 );

    polygon << po + unitVec * bodyLength + perpVec * ( width * 0.5 );

    // second head
    polygon << po + unitVec * bodyLength + perpVec * headSize;
    polygon << pd;
    polygon << po + unitVec * bodyLength - perpVec * headSize;

    polygon << po + unitVec * bodyLength - perpVec * ( width * 0.5 );

    // end of the first head
    polygon << po + unitVec * headSize - perpVec * ( width * 0.5 );
    polygon << po + unitVec * headSize - perpVec * headSize;
  }
  else if ( headType == QgsArrowSymbolLayer::HeadSingle )
  {
    polygon << po - perpVec * ( startWidth * 0.5 );
    polygon << po + perpVec * ( startWidth * 0.5 );
    polygon << po + unitVec * bodyLength + perpVec * ( width * 0.5 );
    polygon << po + unitVec * bodyLength + perpVec * headSize;
    polygon << pd;
    polygon << po + unitVec * bodyLength - perpVec * headSize;
    polygon << po + unitVec * bodyLength - perpVec * ( width * 0.5 );
  }
  else if ( headType == QgsArrowSymbolLayer::HeadReversed )
  {
    // first head
    polygon << po;
    polygon << po + unitVec * headSize + perpVec * headSize;
    polygon << po + unitVec * headSize + perpVec * ( width * 0.5 );

    polygon << pd + perpVec * ( startWidth * 0.5 );
    polygon << pd - perpVec * ( startWidth * 0.5 );

    polygon << po + unitVec * headSize - perpVec * ( width * 0.5 );
    polygon << po + unitVec * headSize - perpVec * headSize;
  }
  // close the polygon
  polygon << polygon.first();

  return polygon;
}
void on_drag(struct bg_point * pos_p) {
#ifndef NDEBUG
    printf("on_drag() %d %d %d\n", pos_p->x, pos_p->y, state);
#endif 
    switch (state) {
        case STATE_LINE_WAITING_RELEASE_FIRST_POINT:
        case STATE_LINE_WAITING_RELEASE_SECOND_POINT:
            bg_undo_restore();
            bg_draw_line(&from, pos_p);
            bg_draw_flush();
            state = STATE_LINE_WAITING_RELEASE_SECOND_POINT;
            break;
        case STATE_LINE_WAITING_CLICK_SECOND_POINT:
            bg_undo_restore();
            bg_draw_line(&from, pos_p);
            bg_draw_flush();
            state = STATE_LINE_WAITING_RELEASE_SECOND_POINT;
            break;

        case STATE_RECTANGLE_WAITING_RELEASE_FIRST_POINT:
        case STATE_RECTANGLE_WAITING_RELEASE_SECOND_POINT:
            bg_undo_restore();
            bg_draw_rectangle(&from, pos_p);
            bg_draw_flush();
            state = STATE_RECTANGLE_WAITING_RELEASE_SECOND_POINT;
            break;
        case STATE_RECTANGLE_WAITING_CLICK_SECOND_POINT:
            bg_undo_restore();
            bg_draw_rectangle(&from, pos_p);
            bg_draw_flush();
            state = STATE_RECTANGLE_WAITING_RELEASE_SECOND_POINT;
            break;

        case STATE_CIRCLE_WAITING_RELEASE_CENTER_POINT:
            center_point = *pos_p;
            state = STATE_CIRCLE_WAITING_RELEASE_POINT_ON_CIRCLE;
            break;
        case STATE_CIRCLE_WAITING_RELEASE_POINT_ON_CIRCLE:
            bg_undo_restore();
            bg_draw_circle(  /* 画圆 */
                    &center_point, 
                    euclidian_distance(center_point, *pos_p));
            bg_draw_line_set_pattern(BG_LINE_PATTERN_3);  /* 切换到虚线 1/8 */
            bg_draw_line(&center_point, pos_p);  /* 辅助线 */
            bg_draw_line_set_pattern(BG_LINE_PATTERN_0);  /* 切换到实线 */
            bg_draw_flush();
            /* state 不变 */
            break;

        case STATE_SELECTION_WAITING_RELEASE_POINT:
            bg_undo_restore();
            bg_draw_line_set_pattern(BG_LINE_PATTERN_2);  /* 切换到虚线 1/4 */
            bg_draw_rectangle(&from, pos_p);
            bg_draw_line_set_pattern(BG_LINE_PATTERN_0);  /* 切换到实线 */
            bg_draw_flush();
            /* state 不变 */
            break;

        case STATE_ROTATE_WAITING_RELEASE:
            bg_undo_restore();
            /* 为了避免辅助线被“刷白”的选区遮挡,要后画辅助线 */
            bg_draw_line_set_pattern(BG_LINE_PATTERN_0);  /* 切换到实线 */
            bg_draw_rotate(
                    &selection_from, &selection_to,
                    &from, pos_p);
            bg_draw_line_set_pattern(BG_LINE_PATTERN_3);  /* 切换到虚线 1/4 */
            bg_draw_line(&from, pos_p);  /* 辅助线 */
            bg_draw_line_set_pattern(BG_LINE_PATTERN_0);  /* 切换到实线 */
            bg_draw_flush();
            /* state 不变 */
            return;

        case STATE_TRANSFORM_WAITING_RELEASE:
            bg_undo_restore();
            /* 为了避免辅助线被“刷白”的选区遮挡,要后画辅助线 */
            bg_draw_line_set_pattern(BG_LINE_PATTERN_0);  /* 切换到实线 */
            tmp.x = pos_p->x - from.x;  /* 使用点 tmp 当作临时变量来表示移动向量 */
            tmp.y = pos_p->y - from.y;
            bg_draw_transform(&selection_from, &selection_to, &tmp);
            bg_draw_line_set_pattern(BG_LINE_PATTERN_3);  /* 切换到虚线 1/4 */
            bg_draw_line(&from, pos_p);  /* 辅助线 */
            bg_draw_line_set_pattern(BG_LINE_PATTERN_0);  /* 切换到实线 */
            bg_draw_flush();
            /* state 不变 */
            
    }
    return;
}
void on_release(struct bg_point * pos_p) {
#ifndef NDEBUG
    printf("on_release() %d %d %d\n", pos_p->x, pos_p->y, state);
#endif  /* NDEBUG */

    /* for SELECTION in switch */
    int minX, maxX;
    int minY, maxY;

    switch (state) {
        case STATE_LINE_WAITING_RELEASE_FIRST_POINT:
            state = STATE_LINE_WAITING_CLICK_SECOND_POINT;
            break;
        case STATE_LINE_WAITING_RELEASE_SECOND_POINT:
            bg_undo_restore();
            bg_draw_line(&from, pos_p);
            bg_undo_commit();
            bg_draw_flush();
            state = STATE_LINE_WAITING_CLICK_FIRST_POINT;
            break;

        case STATE_RECTANGLE_WAITING_RELEASE_FIRST_POINT:
            state = STATE_RECTANGLE_WAITING_CLICK_SECOND_POINT;
            break;
        case STATE_RECTANGLE_WAITING_RELEASE_SECOND_POINT:
            bg_undo_restore();
            bg_draw_rectangle(&from, pos_p);
            bg_undo_commit();
            bg_draw_flush();
            state = STATE_RECTANGLE_WAITING_CLICK_FIRST_POINT;
            break;

        case STATE_POLYLINE_WAITING_RELEASE_FIRST_POINT:
            state = STATE_POLYLINE_WAITING_CLICK_SUBSEQUENT_POINT;
            break;
        case STATE_POLYLINE_WAITING_RELEASE_SUBSEQUENT_POINT:
            bg_undo_restore();
            bg_draw_polyline(&plist, pos_p);
            bg_draw_flush();
            state = STATE_POLYLINE_WAITING_CLICK_SUBSEQUENT_POINT;
            break;

        case STATE_BEZIERCURVE_WAITING_RELEASE_FIRST_POINT:
            state = STATE_BEZIERCURVE_WAITING_CLICK_SUBSEQUENT_POINT;
            break;
        case STATE_BEZIERCURVE_WAITING_RELEASE_SUBSEQUENT_POINT:
            bg_undo_restore();
            bg_draw_line_set_pattern(BG_LINE_PATTERN_3);  /* 切换到虚线 1/8 */
            bg_draw_polyline(&plist, pos_p);  /* 画控制线 */
            bg_draw_line_set_pattern(BG_LINE_PATTERN_0);  /* 切换到实线 */
            bg_draw_beziercurve(&plist, pos_p);
            bg_draw_flush();
            state = STATE_BEZIERCURVE_WAITING_CLICK_SUBSEQUENT_POINT;
            break;

        case STATE_CIRCLE_WAITING_RELEASE_POINT_ON_CIRCLE:
            bg_undo_restore();
            bg_draw_line_set_pattern(BG_LINE_PATTERN_0);  /* 切换到实线 */
            bg_draw_circle(  /* 画圆 */
                    &center_point, 
                    euclidian_distance(center_point, *pos_p));
            bg_undo_commit();  /* 提交更改 */
            bg_draw_flush();
            state = STATE_CIRCLE_WAITING_CLICK_CENTER_POINT;
            break;
        case STATE_CIRCLE_WAITING_RELEASE_CENTER_POINT:
            center_point = *pos_p;
            state = STATE_CIRCLE_WAITING_CLICK_POINT_ON_CIRCLE;
            break;

        case STATE_SELECTION_WAITING_RELEASE_POINT:
#define MIN(a, b) ((a)>(b)?(b):(a))
#define MAX(a, b) ((a)>(b)?(a):(b))
            selection_from = from;
            selection_to = *pos_p;
            minX = MIN(selection_from.x, selection_to.x);
            maxX = MAX(selection_from.x, selection_to.x);
            minY = MIN(selection_from.y, selection_to.y);
            maxY = MAX(selection_from.y, selection_to.y);
            selection_from.x = minX;
            selection_from.y = minY;
            selection_to.x = maxX;
            selection_to.y = maxY;
#undef MIN
#undef MAX
            state = STATE_SELECTION_WAITING_CLICK_POINT;
            break;
case STATE_ROTATE_WAITING_RELEASE:
            bg_undo_restore();
            bg_draw_line_set_pattern(BG_LINE_PATTERN_0);  /* 切换到实线 */
            bg_draw_rotate(
                    &selection_from, &selection_to,
                    &from, pos_p);
            bg_undo_commit();
            bg_draw_flush();
            selection_from.x = selection_from.y = 400;
            selection_to.x = selection_to.y = 400;
            break;

        case STATE_TRANSFORM_WAITING_RELEASE:
            bg_undo_restore();
            bg_draw_line_set_pattern(BG_LINE_PATTERN_0);  /* 切换到实线 */
            tmp.x = pos_p->x - from.x;  /* 使用点 tmp 当作临时变量来表示移动向量 */
            tmp.y = pos_p->y - from.y;
            bg_draw_transform(&selection_from, &selection_to, &tmp);
            bg_undo_commit();
            bg_draw_flush();
            selection_from.x += tmp.x;
            selection_from.y += tmp.y;
            selection_to.x += tmp.x; 
            selection_to.y += tmp.y;
            state = STATE_TRANSFORM_WAITING_PRESS;
            break;
    }
    return;
}